Sign in Join
Wiki copytemporary

Pas2js Transpiler: what changed

Revision 2 to 3. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11## About pas2js
22
33pas2js is a compiler/transpiler to translate programs written in Pascal (subset of Delphi/ObjFPC syntax) to JavaScript.\
44The goal is to use strong typing, while still be able to use low level whenever you choose.\
55The compiled Pascal functions can be used in DOM events or called by JavaScript.\
66pas2js 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:
77
88- file cache - loading, caching files, converting to UTF-8
99- file resolver - handling search paths, finding used units and include files
1010- scanner - reading tokens, handling compiler directives like \$IfDef and \$Include
1111- parser - reading the tokens, checking syntax, creating Pascal nodes
1212- resolver - resolving references, type checking and checking duplicate identifiers
1313- use analyzer - finding unused identifiers, emit hints and warning
1414- converter - translating Pascal nodes into JavaScript nodes
1515- compiler - handling config files, parameters, compiling recursively all used units, writes js
1616- command line interface - a small wrapper to embed the compiler into a console program
1717- library and interface - a small wrapper to embed the compiler into a library
1818
1919Each 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.
2020
2121Note: The modular structure allows to compile any parts or the whole compiler into an IDE addon (not yet started).
2222
2323## Command line parameters
2424
2525Most parameters work the same as their FPC equivalent. pas2js has some options of its own (see -J options).
2626
2727
2828 Options:
2929 Put + after a boolean switch option to enable it, - to disable it
3030 @<x> : Read compiler options from file <x> in addition to the default
3131 pas2js.cfg
3232 -B : Rebuild all
3333 -d<x> : Defines the symbol <x>. Optional: -d<x>:=<value>
3434 -i<x> : Write information and halt. <x> is a combination of the following:
3535 -iD : Write compiler date
3636 -iSO : Write compiler OS
3737 -iSP : Write compiler host processor
3838 -iTO : Write target platform
3939 -iTP : Write target processor
4040 -iV : Write short compiler version
4141 -iW : Write full compiler version
4242 -ic : Write list of supported JS processors usable by -P<x>
4343 -im : Write list of supported modeswitches usable by -M<x>
4444 -io : Write list of supported optimizations usable by -Oo<x>
4545 -it : Write list of supported targets usable by -T<x>
4646 -iJ : Write list of supported JavaScript identifiers -JoRTL-<x>
4747 -C<x> : Code generation options. <x> is a combination of the following
4848 letters:
4949 o : Overflow checking of integer operations
5050 r : Range checking
5151 R : Object checks. Verify method calls and object type casts.
5252 -F... Set file names and paths:
5353 -Fe<x>: Redirect output to file <x>. UTF-8 encoded.
5454 -FE<x>: Set main output path to <x>
5555 -Fi<x>: Add <x> to include paths
5656 -FN<x>: add <x> to namespaces. Namespaces with trailing - are removed.
5757 Delphi calls this flag "unit scope names".
5858 -Fu<x>: Add <x> to unit paths
5959 -FU<x>: Set unit output path to <x>
6060 -I<x> : Add <x> to include paths, same as -Fi
6161 -J... Extra options of pas2js
6262 -Ja<x>: Append JS file <x> to main JS file. E.g. -Jamap.js. Can be given
6363 multiple times. To remove a file name append a minus, e.g.
6464 -Jamap.js-.
6565 -Jc : Write all JavaScript concatenated into the output file
6666 -Je<x>: Encode messages as <x>.
6767 -Jeconsole: Console codepage. This is the default.
6868 -Jesystem : System codepage. On non Windows console and system are the
6969 same.
7070 -Jeutf-8 : Unicode UTF-8. Default when using -Fe.
7171 -JeJSON : Output compiler messages as JSON. Logo etc are outputted
7272 as-is.
7373 -Ji<x>: Insert JS file <x> into main JS file. E.g. -Jirtl.js. Can be given
7474 multiple times. To remove a file name append a minus, e.g.
7575 -Jirtl.js-.
7676 -Jl : lower case identifiers
7777 -Jm : generate source maps
7878 -Jmsourceroot=<x>: use x as "sourceRoot", prefix URL for source file
7979 names.
8080 -Jmbasedir=<x>: write source file names relative to directory x, default
8181 is map file folder.
8282 -Jminclude: include Pascal sources in source map.
8383 -Jmabsolute: store absolute filenames, not relative.
8484 -Jmxssiheader: start source map with XSSI protection )]}', default.
8585 -Jm-: disable generating source maps
8686 -Jo<x>: Enable or disable extra option. The x is case insensitive:
8787 -JoSearchLikeFPC: search source files like FPC, default: search case
8888 insensitive.
8989 -JoUseStrict: add "use strict" to modules, default.
9090 -JoCheckVersion-: do not add rtl version check, default.
9191 -JoCheckVersion=main: insert rtl version check into main.
9292 -JoCheckVersion=system: insert rtl version check into system unit init.
9393 -JoCheckVersion=unit: insert rtl version check into every unit init.
9494 -JoRTL-<y>=<z>: set RTL identifier y to value z. See -iJ.
9595 -Jr<x> Control writing of resource string file
9696 -Jrnone: Do not write resource string file
9797 -Jrunit: Write resource string file per unit with all resource strings
9898 -Jrprogram: Write resource string file per program with all used
9999 resource strings in program
100100 -JR<x> Control writing of linked resources
101101 -JRnone: Skip resource directives
102102 -JRjs: Write resources in Javascript structure
103103 -JRhtml[=filename] : Write resources as preload links in HTML file
104104 (default is projectfile-res.html)
105105 -Jpcmd<command>: Run postprocessor. For each generated js execute command
106106 passing the js as stdin and read the new js from stdout. This
107107 option can be added multiple times to call several postprocessors
108108 in succession.
109109 -Ju<x>: Add <x> to foreign unit paths. Foreign units are not compiled.
110110 -JU: This pas2js does not support PCU files
111111 -l : Write logo
112112 -M<x> : Set language mode or enable/disable a modeswitch
113113 -MDelphi: Delphi 7 compatibility mode
114114 -MObjFPC: FPC's Object Pascal compatibility mode (default)
115115 -M<x> : enable or disable modeswitch, see option -im
116116 Each mode (as listed above) enables its default set of modeswitches.
117117 Other modeswitches are disabled and need to be enabled one by another.
118118 -NS<x> : obsolete: add <x> to namespaces. Same as -FN<x>
119119 -n : Do not read the default config files
120120 -o<x> : Change main JavaScript file to <x>, "." means stdout
121121 -O<x> : Optimizations:
122122 -O- : Disable optimizations
123123 -O1 : Level 1 optimizations (quick and debugger friendly)
124124 -O2 : Level 2 optimizations (Level 1 + not debugger friendly)
125125 -Oo<x>: Enable or disable optimization. The x is case insensitive:
126126 -OoEnumNumbers[-]: write enum value as number instead of name. Default
127127 in -O1.
128128 -OoRemoveNotUsedPrivates[-]: Default is enabled
129129 -OoRemoveNotUsedDeclarations[-]: Default enabled for programs with -Jc
130130 -OoRemoveNotUsedPublished[-] : Default is disabled
131131 -OoShortRefGlobals[-]: Insert JS local var for types, modules and
132132 static functions. Default enabled in -O2
133133 -P<x> : Set target processor. Case insensitive:
134134 -Pecmascript5: default
135135 -Pecmascript6
136136 -S<x> : Syntax options. <x> is a combination of the following letters:
137137 2 : Same as -Mobjfpc (default)
138138 a : Turn on assertions
139139 c : Support operators like C (*=,+=,/= and -=)
140140 d : Same as -Mdelphi
141141 j : Allows typed constants to be writeable (default)
142142 m : Enables macro replacements
143143 -SI<x> : Set interface style to <x>
144144 -SIcom : COM, reference counted interface (default)
145145 -SIcorba: CORBA interface
146146 -T<x> : Set target platform
147147 -Tbrowser: default
148148 -Tnodejs : add pas.run(), includes -Jc
149149 -Telectron: experimental
150150 -Tmodule : add pas.run(), includes -Jc
151151 -u<x> : Undefines the symbol <x>
152152 -v<x> : Be verbose. <x> is a combination of the following letters:
153153 e : Show errors (default)
154154 w : Show warnings
155155 n : Show notes
156156 h : Show hints
157157 i : Show info
158158 l : Show line numbers, needs -vi
159159 a : Show everything
160160 0 : Show nothing (except errors)
161161 b : Show file names with full path
162162 c : Show conditionals
163163 t : Show tried/used files
164164 d : Show debug notes and info, enables -vni
165165 q : Show message numbers
166166 x : Show used tools
167167 v : Write pas2jsdebug.log with lots of debugging info
168168 z : Write messages to stderr, -o. still uses stdout.
169169 -vm<x>,<y>: Do not show messages numbered <x> and <y>.
170170 -? : Show this help
171171 -h : Show this help
172172
173173 Environment variable PAS2JS_OPTS is parsed after default config and before
174174 command line parameters.
175175
176176## Delphi and ObjFPC mode
177177
178178### Delphi mode
179179
180180- Defines macro *DELPHI*
181181- Assigning a function to a function type variable does not require the @ operator. For example, you can write either *OnGetThing:=GetValue;* or *OnGetThing:=@GetValue;*.
182182- A function type variable reference without brackets is treated as a call. For example: If *OnGetThing* is a variable of type *function: integer* you can write: *If OnGetThing=3 then ;*.
183183- You must use the @@ operator to get the procedure address (i.e. JS reference) of a procedure type variable. For example instead of *If OnClick=nil then ;* you must use *if @@OnClick=nil then ;*.
184184- Every procedure/method overload needs the 'overload' modifier.
185185
186186### ObjFPC mode
187187
188188This the default mode of pas2js and is generally more strict than the Delphi mode, and allows some more operations.
189189
190190- Defines macro *OBJFPC*
191191- Assigning a function to a function type variable requires the @ operator. For example: *OnGetThing:=@GetValue;*.
192192- A function type variable always needs brackets to be called. For example: If *OnGetThing* is a variable of type *function: integer* then this is allowed: *If OnGetThing()=3 then ;*. While this gives an error: *If OnGetThing=3 then ;*.
193193- You can compare a procedure type with *nil*. For example *If OnClick=nil then ;*.
194194- You can compare a procedure type with a procedure address (i.e. JS reference). For example *If OnClick=@OnFormClick then ;*.
195195- 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.
196196
197197## Translating modules
198198
199199A Pascal Program is translated into the following JavaScript structure:
200200
201201**Pascal**
202202
203203**JavaScript Structure, not code!**
204204
205205 Program &lt;unitname&gt;;
206206 Implementation
207207 [implementation section]
208208 Begin
209209 [main code]
210210 End.
211211
212212 pas.&lt;program&gt;={
213213 [implementation section],
214214 $main: function() {
215215 [main code]
216216 }
217217 };
218218
219219
220220A Pascal Unit is translated into the following JavaScript structure:
221221
222-<thead>
223-
224-</thead>
225-<tbody>
226-
227-<code>Interface</code><br />
228-<code>  [interface section]</code><br />
229-<code>Implementation</code><br />
230-<code>  [implementation section]</code><br />
231-<code>Initialization</code><br />
232-<code>  [initialization section]</code><br />
233-<code>End.</code></td>
234-
235-<code>  [interface section],</code><br />
236-<code>  $impl: {</code><br />
237-<code>    [implementation section],</code><br />
238-<code>  },</code><br />
239-<code>  $init: function() {</code><br />
240-<code>    [initialization section]</code><br />
241-<code>  }</code><br />
242-<code>};</code></td>
243-
244-</tbody>
222+| Pascal | JavaScript Structure, not code! |
223+|---|---|
224+| `Unit <unitname>;` · `Interface` · ` [interface section]` · `Implementation` · ` [implementation section]` · `Initialization` · ` [initialization section]` · `End.` | `pas.<unitname>={` · ` [interface section],` · ` $impl: {` · ` [implementation section],` · ` },` · ` $init: function() {` · ` [initialization section]` · ` }` · `};` |
245225
246226Note: The **finalization** section is not supported by pas2js.\
247227
248228To create and initialize the units in topological order the compiler translates an Unit to the following JavaScript code:
249229
250-<thead>
251-
252-</thead>
253-<tbody>
254-
255-<code>Interface</code><br />
256-<code>  [interface section]</code><br />
257-<code>Implementation</code><br />
258-<code>  [implementation section]</code><br />
259-<code>Initialization</code><br />
260-<code>  [initialization section]</code><br />
261-<code>End.</code></td>
262-
263-<code>  ['system',...other used units of the interface section...],</code><br />
264-<code>  function(){</code><br />
265-<code>    var $mod = this;</code><br />
266-<code>    var $impl = $mod.$impl;</code><br />
267-<code>    [interface section]</code><br />
268-<code>    $mod.$implcode = function(){</code><br />
269-<code>      [implementation section]</code><br />
270-<code>    }</code><br />
271-<code>    $mod.$init = function(){</code><br />
272-<code>      [initialization section]</code><br />
273-<code>    };</code><br />
274-<code>  },</code><br />
275-<code>  [...used units of the implementation section]</code><br />
276-<code>  };</code></td>
277-
278-</tbody>
230+| Pascal | JavaScript |
231+|---|---|
232+| `Unit <unitname>;` · `Interface` · ` [interface section]` · `Implementation` · ` [implementation section]` · `Initialization` · ` [initialization section]` · `End.` | `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]` · ` };` |
279233
280234Here is a more detailed example to make it more clear:
281235
282-<thead>
283-
284-</thead>
285-<tbody>
286-
287-<code>Interface</code><br />
288-<code>Uses Sysutils;</code><br />
289-<code>var</code><br />
290-<code>  dIntf: double;</code><br />
291-<code>  sIntf: string = 'abc';</code><br />
292-<code>procedure MyIntfProc;</code><br />
293-<code>Implementation</code><br />
294-<code>Uses Classes;</code><br />
295-<code>Var dImpl:double;</code><br />
296-<code>Procedure MyIntfProc;</code><br />
297-<code>Begin</code><br />
298-<code>  dImpl:=dIntf;</code><br />
299-<code>End;</code><br />
300-<code>Procedure MyImplProc;</code><br />
301-<code>Begin</code><br />
302-<code>  dImpl:=dIntf;</code><br />
303-<code>End;</code><br />
304-<code>Initialization</code><br />
305-<code>End.</code></td>
306-
307-<code>["System","SysUtils"],</code><br />
308-<code>function(){</code><br />
309-<code>  var $mod = this;</code><br />
310-<code>  var $impl = $mod.$impl;</code><br />
311-<code>  this.dIntf = 0.0;</code><br />
312-<code>  this.sIntf = "abc";</code><br />
313-<code>  this.MyIntfProc = function(){</code><br />
314-<code>    $impl.dImpl = $mod.dIntf;</code><br />
315-<code>  };</code><br />
316-<code>  $mod.$implcode = function(){</code><br />
317-<code>    $impl.dImpl = 0.0;</code><br />
318-<code>    $impl.MyImplProc = function() {</code><br />
319-<code>      $impl.dImpl = $mod.dIntf;</code><br />
320-<code>    };</code><br />
321-<code>  }</code><br />
322-<code>  $mod.$init = function() {</code><br />
323-<code>  };</code><br />
324-<code>},</code><br />
325-<code>["Classes"]);</code></td>
326-
327-</tbody>
236+| Pascal | JavaScript |
237+|---|---|
238+| `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.` | `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"]);` |
328239
329240Notes:
330241
331242- Unit *System* is always loaded implicitely.
332243- References to other units are translated to full path. For example *TObject* is translated to *pas.system.TObject*
333244- References to dotted unitnames, aka units with namespaces are translated to *pas\["namespace.unitname"\]*.
334245
335246## Translating variables
336247
337248Variables are converted without type, because JavaScript lacks a clear type. They are however always initialized, which helps JavaScript engines to optimize.
338249
339-<thead>
340-
341-</thead>
342-<tbody>
343-
344-<code>Interface</code><br />
345-<code>Uses Classes,Forms;</code><br />
346-<code>const</code><br />
347-<code>  c1:integer=3;</code><br />
348-<code>  c2 = 'abc';</code><br />
349-<code>  c3 = 234;</code><br />
350-<code>  c4 = 12.45;</code><br />
351-<code>  c5 = nil;</code><br />
352-<code>var</code><br />
353-<code>  v1:string;</code><br />
354-<code>  v2,v3:double;</code><br />
355-<code>  v4:byte=0;</code><br />
356-<code>  v5:TForm;</code><br />
357-<code>  v6:TIdentMapEntry;</code><br />
358-<code>  v7:string='abc';</code><br />
359-<code>  v8:char='c';</code><br />
360-<code>  v9:array of byte;</code><br />
361-<code>Implementation</code><br />
362-<code>End.</code></td>
363-
364-<code>["System","Classes","Forms"],</code><br />
365-<code>function(){</code><br />
366-<code>  this.c1 = 3;</code><br />
367-<code>  this.c2 = "abc";</code><br />
368-<code>  this.c3 = 234;</code><br />
369-<code>  this.c4 = 12.45;</code><br />
370-<code>  this.c5 = null;</code><br />
371-<code>  this.v1 = "";</code><br />
372-<code>  this.v2 = 0.0;</code><br />
373-<code>  this.v3 = 0.0;</code><br />
374-<code>  this.v4 = 0;</code><br />
375-<code>  this.v5 = null;</code><br />
376-<code>  this.v6 = new pas.Classes.TIdentMapEntry();</code><br />
377-<code>  this.v7 = "abc";</code><br />
378-<code>  this.v8 = "c";</code><br />
379-<code>  this.v9 = [];</code><br />
380-<code>},</code><br />
381-<code>[]);</code></td>
382-
383-</tbody>
250+| Pascal | JavaScript |
251+|---|---|
252+| `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.` | `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 = [];` · `},` · `[]);` |
384253
385254Notes:
386255
387256- Type casting a *boolean* to *integer*, gives *0* for *false* and *1* for *true*.
388257- Type casting an *integer* to *boolean*, gives *false* for *0* and *true* otherwise.
389258- A **char** is translated to a JS string, because JS lacks a native char type.
390259- A **char** is a single JS char code. An UTF-16 codepoint can contain one or two **char**.
391260- **Integers overflows** at runtime differ from Delphi/FPC, due to the double format. For example adding *var i: byte = 200; ... i:=i+100;* will result in *i=300* instead of *i=44* as in Delphi/FPC. When range checking *{\$R+}* is enabled *i:=300* will raise an ERangeError.
392261- **type cast integer to integer**, e.g. *byte(aLongInt)*
393262 - with range checking enabled: error if outside range
394263 - without range checking: emulates the FPC/Delphi behaviour: e.g. *byte(value)* translates to *value & 0xff*, *shortint(value)* translates to *value & 0xff \<\<24 \>\> 24.*
395264- The **mod-operator** works 32-bit signed in JS.
396265
397266## Translating string
398267
399268Strings are translated to JavaScript strings. They are initialized with "" and are never **null**.\
400269There are no *ShortString, AnsiString or RawByteString*. *Unicodestring* and *Widestring* are alias of *String*.\
401270JavaScript strings are immutable, which means that changing a single character in a string, creates a new string. So a *s\[2\]:='c';* is a slow operation in pas2js compared to Delphi/FPC.\
402271Although 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 *char*, and a visible glyph can need several codepoints. Same as in Delphi.
403272
404273## Translating resourcestrings
405274
406275Resourcestrings are translated to JS objects with original (org) and current value.
407276
408-<thead>
409-
410-</thead>
411-<tbody>
412-
413-<code>Interface</code><br />
414-<code>resourcestring</code><br />
415-<code>  rsCompiler = 'pas2js';</code><br />
416-<code>var</code><br />
417-<code>  s:string;</code><br />
418-<code>Implementation</code><br />
419-<code>initialization</code><br />
420-<code>  s:=rsCompiler;</code><br />
421-<code>End.</code></td>
422-
423-<code>  var $mod = this;</code><br />
424-<code>  this.s = "";</code><br />
425-<code>  $mod.$resourcestrings = {rsCompiler: {org: "pas2js"}};</code><br />
426-<code>  $mod.$init = function () {</code><br />
427-<code>    $mod.s = rtl.getResStr(pas.test1,"rsCompiler");</code><br />
428-<code>  };</code><br />
429-<code>});</code></td>
430-
431-</tbody>
277+| Pascal | JavaScript |
278+|---|---|
279+| `Unit MyModule;` · `Interface` · `resourcestring` · ` rsCompiler = 'pas2js';` · `var` · ` s:string;` · `Implementation` · `initialization` · ` s:=rsCompiler;` · `End.` | `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");` · ` };` · `});` |
432280
433281## Translating currency
434282
435283*Currency* in Delphi/FPC is an int64 with a factor of 10000. This is translated to a double with factor 10000 and truncated.
436284
437285- *CurA := 1.12345* -\> *CurA = 11234*
438286- *CurA + CurB* -\> *CurA + CurB*
439287- *CurA * CurB* -\> *CurA * CurB/10000*
440288- *CurA / CurB* -\> *Math.floor(CurA/CurB * 10000)*
441289- *CurA ^^ CurB* -\> *Math.floor(Math.pow(CurA/10000,CurB/10000) * 10000)*
442290- *Currency + Double* -\> *Currency + (Double*10000)*
443291- *Double := Currency* -\> *Double = Currency/10000*
444292- *Currency := Double* -\> *Currency = Math.floor(Double*10000)*
445293- *JSValue := Currency* -\> *JSValue = Currency/10000*
446294- 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
447295
448296## Translating Types
449297
450298JavaScript 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.\
451299Complex Pascal types (classes, records, or arrays) are translated into JavaScript objects or arrays respectively.\
452300
453301## Translating pointer
454302
455303A *pointer* 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 *isArray*, *isClass*, *isClassRef*, *isCallback*, etc of unit *JS*.
456304
457305## Translating record type
458306
459307A record is translated to a JavaScript object.
460308
461-<thead>
462-
463-</thead>
464-<tbody>
465-
466-<code>Interface</code><br />
467-<code>Type</code><br />
468-<code>  TMyRecord = Record</code><br />
469-<code>    i: integer;</code><br />
470-<code>    s: string;</code><br />
471-<code>    d: TDateTime;</code><br />
472-<code>  End;</code><br />
473-<code>Var</code><br />
474-<code>  r, s: TMyRecord;</code><br />
475-<code>Implementation</code><br />
476-<code>Initialization</code><br />
477-<code>  r.i := 123;</code><br />
478-<code>  r:=s;</code><br />
479-<code>  if r=s then ;</code><br />
480-<code>End.</code></td>
481-
482-<code>["System"],</code><br />
483-<code>function(){</code><br />
484-<code>  var $mod = this;</code><br />
485-<code>  rtl.recNewT($mod, "TMyRecord", function() {</code><br />
486-<code>    this.i = 0;</code><br />
487-<code>    this.s = "";</code><br />
488-<code>    this.d = 0.0;</code><br />
489-<code>    this.$eq = function (b) {</code><br />
490-<code>      return (this.i == b.i) &amp;&amp;</code><br />
491-<code>         (this.s == b.i) &amp;&amp; (this.d == b.d);</code><br />
492-<code>    };</code><br />
493-<code>    this.$assign = function (s) {</code><br />
494-<code>      this.i = s.i;</code><br />
495-<code>      this.s = s.s;</code><br />
496-<code>      this.d = s.d;</code><br />
497-<code>      return this;</code><br />
498-<code>    };</code><br />
499-<code>  };</code><br />
500-<code>  this.r = this.TMyRecord.$new();</code><br />
501-<code>  $mod.$init = function() {</code><br />
502-<code>    $mod.r.i=123;</code><br />
503-<code>    $mod.r.$assign($mod.s);</code><br />
504-<code>    if ($mod.r.$eq($mod.s)) ;</code><br />
505-<code>  },</code><br />
506-<code>},</code><br />
507-<code>[]);</code></td>
508-
509-<code>["System"],</code><br />
510-<code>function(){</code><br />
511-<code>  var $mod = this;</code><br />
512-<code>  this.TMyRecord = function(s) {</code><br />
513-<code>    if (s){</code><br />
514-<code>      this.i = s.i;</code><br />
515-<code>      this.s = s.s;</code><br />
516-<code>      this.d = s.d;</code><br />
517-<code>    } else {</code><br />
518-<code>      this.i = 0;</code><br />
519-<code>      this.s = "";</code><br />
520-<code>      this.d = 0.0;</code><br />
521-<code>    };</code><br />
522-<code>    this.$equal = function (b) {</code><br />
523-<code>      return (this.i == b.i) &amp;&amp;</code><br />
524-<code>        (this.s == b.i) &amp;&amp; (this.d == b.d);</code><br />
525-<code>    };</code><br />
526-<code>  };</code><br />
527-<code>  this.r = new this.TMyRecord();</code><br />
528-<code>  $mod.$init = function() {</code><br />
529-<code>    $mod.r.i=123;</code><br />
530-<code>    $mod.r = new $mod.TMyRecord($mod.s);</code><br />
531-<code>    if ($mod.r.$equal($mod.s)) ;</code><br />
532-<code>  },</code><br />
533-<code>},</code><br />
534-<code>[]);</code></td>
535-
536-</tbody>
309+| Pascal | JS Pas2js 1.3 | JS Pas2js 1.2 |
310+|---|---|---|
311+| `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.` | `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)) ;` · ` },` · `},` · `[]);` | `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)) ;` · ` },` · `},` · `[]);` |
537312
538313- The record variable creates a JavaScript object.
539314- Variant records are not supported.
540315- Supported: Assign, pass as argument, equal, not equal, array of record, pointer of record, const, default(), RTTI.
541316- Advanced record (since pas2js 1.3):
542317 - visibility private, strict private, public, default is public
543318 - methods, class methods (must be static like in Delphi/FPC)
544319 - class vars
545320 - const fields
546321 - property, class property, array property, default array property
547322 - sub types
548323 - constructor
549324 - class constructor
550325- Not yet implemented:
551326 - operator overloading
552327 - reference counted interfaces as fields
553328 - Interfaces as nested types
554329 - default non array property
555330- 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.
556331- Since record types are JS objects it is possible to typecast a record type to the JS Object, e.g. *TJSObject(TPoint)*. Note that you cannot typecast directly to a *TJSObject* descendant. You can use *TJSWindow(TJSObject(aRecord))*.
557332- A pointer of record is simply a reference.
558333 - *p:=@r* translates to *p=r*
559334 - *p^.x* becomes *p.x*.
560335 - *New(PointerOfRecord)* creates a new record
561336 - *Dispose(PointerOfRecord)* Sets the variable to null if possible.
562337- 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.
563338- Typecasting RecordType(UntypedArgument) returns the argument, i.e. no conversion.
564339
565340## Translating generics
566341
567342Generics are not translated, their specializations are.
568343
569344- Specializations are created with a \$ number postfix, for example **TList\$G3**.
570345- Their RTTI name has the full name, for example **TList\<project1.TBird\>**
571346- Multiple specializations of *TList\<word\>* creates only one specialization. That is true for the whole program.
572347- Specializations are created in the unit, where the generic is defined, not where they are specialized.
573348- Important: This means that a new specialization of *TList* require a recompile of the js of unit *generics.collections*.
574349
575350## Translating functions
576351
577-<thead>
578-
579-</thead>
580-<tbody>
581-
582-<code>Interface</code><br />
583-<code>Function DoubleIt(n: integer): integer;</code><br />
584-<code>Implementation</code><br />
585-<code>Function DoubleIt(n: integer): integer;</code><br />
586-<code>Begin</code><br />
587-<code>  Result:=2*n;</code><br />
588-<code>End;</code><br />
589-<code>End.</code></td>
590-
591-<code>["System"],</code><br />
592-<code>function(){</code><br />
593-<code>  this.DoubleIt = function(n){</code><br />
594-<code>    Result = 0;</code><br />
595-<code>    Result = 2*n;</code><br />
596-<code>    return Result;</code><br />
597-<code>  };</code><br />
598-<code>},</code><br />
599-<code>[]);</code></td>
600-
601-</tbody>
352+| Pascal | JavaScript |
353+|---|---|
354+| `Unit MyModule;` · `Interface` · `Function DoubleIt(n: integer): integer;` · `Implementation` · `Function DoubleIt(n: integer): integer;` · `Begin` · ` Result:=2*n;` · `End;` · `End.` | `rtl.module("MyModule",` · `["System"],` · `function(){` · ` this.DoubleIt = function(n){` · ` Result = 0;` · ` Result = 2*n;` · ` return Result;` · ` };` · `},` · `[]);` |
602355
603356Notes:
604357
605358- Local variables become local JavaScript variables: *var l = 0;*.
606359- Local constants become JavaScript variables in the unit/program implementation section.
607360- Local types are elevated to module.
608361- Overloaded functions are given an unique name by appending \$1, \$2, ...
609362- Supported: default values, const/var/out/default, FuncName:=
610363
611364## Translating passing a parameter by reference
612365
613366JavaScript lacks passing by reference. Instead a temporary object is created with a *get* and *set* function. That means changes within the procedure are immediately visible outside, compatible with Pascal.
614367
615-<thead>
616-
617-</thead>
618-<tbody>
619-
620-<code>Procedure DoubleIt(var n: integer);</code><br />
621-<code>Begin</code><br />
622-<code>  n:=2*n;</code><br />
623-<code>End;</code><br />
624-<code>Function Doubling(n: integer): integer;</code><br />
625-<code>Begin</code><br />
626-<code>  DoubleIt(n);</code><br />
627-<code>  Result:=n;</code><br />
628-<code>End;</code><br />
629-<code>Var</code><br />
630-<code>  i: integer = 7;</code><br />
631-<code>Begin</code><br />
632-<code>  Doubling(i);</code><br />
633-<code>End.</code></td>
634-
635-<code>["System"],</code><br />
636-<code>function(){</code><br />
637-<code>  var $mod = this;</code><br />
638-<code>  this.i = 7;</code><br />
639-<code>  this.DoubleIt = function(n){</code><br />
640-<code>    n.set(2*n.get());</code><br />
641-<code>  };</code><br />
642-<code>  this.Doubling = function(n){</code><br />
643-<code>    var Result = 0;</code><br />
644-<code>    DoubleIt({</code><br />
645-<code>      get:function(){</code><br />
646-<code>        return n</code><br />
647-<code>      },</code><br />
648-<code>      set:function(v){</code><br />
649-<code>        n=v;</code><br />
650-<code>      }</code><br />
651-<code>    });</code><br />
652-<code>    Result = n;</code><br />
653-<code>    return n;</code><br />
654-<code>  };</code><br />
655-<code>  $mod.$main = function(){</code><br />
656-<code>    Doubling($mod.i);</code><br />
657-<code>  }</code><br />
658-<code>},</code><br />
659-<code>[]);</code></td>
660-
661-</tbody>
368+| Pascal | JavaScript |
369+|---|---|
370+| `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.` | `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);` · ` }` · `},` · `[]);` |
662371
663372When the passed value is from another context, the context is passed too:
664373
665-<thead>
666-
667-</thead>
668-<tbody>
669-
670-<code>Procedure DoubleIt(var n: integer);</code><br />
671-<code>Begin</code><br />
672-<code>  n:=2*n;</code><br />
673-<code>End;</code><br />
674-<code>Var</code><br />
675-<code>  i: integer = 7;</code><br />
676-<code>Begin</code><br />
677-<code>  DoubleIt(i);</code><br />
678-<code>End.</code></td>
679-
680-<code>["System"],</code><br />
681-<code>function(){</code><br />
682-<code>  var $mod = this;</code><br />
683-<code>  this.i = 7;</code><br />
684-<code>  this.DoubleIt = function(n){</code><br />
685-<code>    n.set(2*n.get());</code><br />
686-<code>  };</code><br />
687-<code>  $mod.$main = function(){</code><br />
688-<code>    DoubleIt({</code><br />
689-<code>        p:$mod,</code><br />
690-<code>        get:function(){</code><br />
691-<code>          return this.p.i</code><br />
692-<code>        },</code><br />
693-<code>        set:function(v){</code><br />
694-<code>          this.p.i=v;</code><br />
695-<code>        }</code><br />
696-<code>      });</code><br />
697-<code>  }</code><br />
698-<code>},</code><br />
699-<code>[]);</code></td>
700-
701-</tbody>
374+| Pascal | JavaScript |
375+|---|---|
376+| `Program MyModule;` · `Procedure DoubleIt(var n: integer);` · `Begin` · ` n:=2*n;` · `End;` · `Var` · ` i: integer = 7;` · `Begin` · ` DoubleIt(i);` · `End.` | `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;` · ` }` · ` });` · ` }` · `},` · `[]);` |
702377
703378Notes:
704379
705380- Contrary to Delphi/FPC it is allowed to pass a property to a var/out parameter.
706381
707382## Translating nested functions
708383
709384A nested function is translated to a local variable.
710385
711-<thead>
712-
713-</thead>
714-<tbody>
715-
716-<code>Interface</code><br />
717-<code>Function SumNNumbers(n, Adder: integer): integer;</code><br />
718-<code>Implementation</code><br />
719-<code>Function SumNNumbers(n, Adder: integer): integer;</code><br />
720-
721-<code>  Function Add(k: integer): integer;</code><br />
722-<code>  Begin</code><br />
723-<code>    if k=1 then</code><br />
724-<code>      Result:=1</code><br />
725-<code>    else</code><br />
726-<code>      Result:=Add(k-1)+Adder;</code><br />
727-<code>  End;</code><br />
728-
729-<code>Begin</code><br />
730-<code>  Result:=Add(n);</code><br />
731-<code>End;</code><br />
732-<code>End.</code></td>
733-
734-<code>["System"],</code><br />
735-<code>function(){</code><br />
736-<code>  this.DoubleIt = function(n,Adder){</code><br />
737-<code>    Result = 0;</code><br />
738-<code>    var Add = function(k) {</code><br />
739-<code>      Result = 0;</code><br />
740-<code>      if (k==1) {</code><br />
741-<code>        Result = 1;</code><br />
742-<code>      } else {</code><br />
743-<code>        Result = Add(k-1)+Adder;</code><br />
744-<code>      }</code><br />
745-<code>      return Result;</code><br />
746-<code>    };</code><br />
747-<code>    Result = Add(n);</code><br />
748-<code>    return Result;</code><br />
749-<code>  };</code><br />
750-<code>},</code><br />
751-<code>[]);</code></td>
752-
753-</tbody>
386+| Pascal | JavaScript |
387+|---|---|
388+| `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.` | `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;` · ` };` · `},` · `[]);` |
754389
755390Note: You can assign a nested procedure to a procedure variable. A nested procedure of a method can be assigned to a method variable.\
756391JavaScript preserves the current local scope, including references to the local variables of parent functions. Local types and constants belong to the unit scope (singleton).\
757392When a method has nested functions, the compiler adds a local var *Self*.
758393
759394## Translating for-loops
760395
761396The 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.
762397
763-<thead>
764-
765-</thead>
766-<tbody>
767-
768-<code>Interface</code><br />
769-<code>Function SumNNumbers(n: integer): integer;</code><br />
770-<code>Implementation</code><br />
771-<code>Function SumNNumbers(n: integer): integer;</code><br />
772-<code>Var</code><br />
773-<code>  i, j: integer;</code><br />
774-<code>Begin</code><br />
775-<code>  j:=0;</code><br />
776-<code>  For i:=1 To n Do</code><br />
777-<code>  Begin</code><br />
778-<code>    j:=j+i;</code><br />
779-<code>  End;</code><br />
780-<code>  if i&lt;1 then j:=1;</code><br />
781-<code>  Result:=j;</code><br />
782-<code>End;</code><br />
783-<code>End.</code></td>
784-
785-<code>["System"],</code><br />
786-<code>function(){</code><br />
787-<code>  this.SumNNumbers=function(n){</code><br />
788-<code>    Result = 0;</code><br />
789-<code>    j = 0;</code><br />
790-<code>    for (var $l1 = 1, $le2 = n; $l1 &lt;= $le2; $l1++) {</code><br />
791-<code>      i = $l1;</code><br />
792-<code>      j = j + i;</code><br />
793-<code>    };</code><br />
794-<code>    if (i&lt;1) j=1;</code><br />
795-<code>    Result = j;</code><br />
796-<code>    return Result;</code><br />
797-<code>  };</code><br />
798-<code>},</code><br />
799-<code>[]);</code></td>
800-
801-</tbody>
398+| Pascal | JavaScript |
399+|---|---|
400+| `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.` | `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;` · ` };` · `},` · `[]);` |
802401
803402Note: The after-loop decrement is only added if *i* is read after the loop.\
804403
805404## Translating repeat..until
806405
807406The *repeat..until* is translated to a *do{}while()*.
808407
809-<thead>
810-
811-</thead>
812-<tbody>
813-
814-<code>Interface</code><br />
815-<code>Function SumNNumbers(n: integer): integer;</code><br />
816-<code>Implementation</code><br />
817-<code>Function SumNNumbers(n: integer): integer;</code><br />
818-<code>Var</code><br />
819-<code>  i, j: integer;</code><br />
820-<code>Begin</code><br />
821-<code>  j:=0;</code><br />
822-<code>  i:=0;</code><br />
823-<code>  Repeat</code><br />
824-<code>    i:=i+1;</code><br />
825-<code>    j:=j+i;</code><br />
826-<code>  Until i&gt;=n;</code><br />
827-<code>  Result:=j;</code><br />
828-<code>End;</code><br />
829-<code>End.</code></td>
830-
831-<code>["System"],</code><br />
832-<code>function(){</code><br />
833-<code>  this.SumNNumbers=function(n){</code><br />
834-<code>    Result = 0;</code><br />
835-<code>    j = 0;</code><br />
836-<code>    i = 0;</code><br />
837-<code>    do{</code><br />
838-<code>      i = (i + 1);</code><br />
839-<code>      j = (j + i);</code><br />
840-<code>    } while (!(i&gt;=n));</code><br />
841-<code>    Result = j;</code><br />
842-<code>    return Result;</code><br />
843-<code>  };</code><br />
844-<code>},</code><br />
845-<code>[]);</code></td>
846-
847-</tbody>
408+| Pascal | JavaScript |
409+|---|---|
410+| `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.` | `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;` · ` };` · `},` · `[]);` |
848411
849412## Translating while..do
850413
851-<thead>
852-
853-</thead>
854-<tbody>
855-
856-<code>Interface</code><br />
857-<code>Function SumNNumbers(n: integer): integer;</code><br />
858-<code>Implementation</code><br />
859-<code>Function SumNNumbers(n: integer): integer;</code><br />
860-<code>Var</code><br />
861-<code>  i, j: integer;</code><br />
862-<code>Begin</code><br />
863-<code>  j:=0;</code><br />
864-<code>  i:=0;</code><br />
865-<code>  While i&lt;n Do Begin</code><br />
866-<code>    i:=i+1;</code><br />
867-<code>    j:=j+i;</code><br />
868-<code>  End;</code><br />
869-<code>  Result:=j;</code><br />
870-<code>End;</code><br />
871-<code>End.</code></td>
872-
873-<code>["System"],</code><br />
874-<code>function(){</code><br />
875-<code>  this.SumNNumbers=function(n){</code><br />
876-<code>    var Result = 0;</code><br />
877-<code>    var j = 0;</code><br />
878-<code>    var i = 0;</code><br />
879-<code>    while(i&lt;n){</code><br />
880-<code>      i = (i + 1);</code><br />
881-<code>      j = (j + i);</code><br />
882-<code>    };</code><br />
883-<code>    Result = j;</code><br />
884-<code>    return Result;</code><br />
885-<code>  };</code><br />
886-<code>},</code><br />
887-<code>[]);</code></td>
888-
889-</tbody>
414+| Pascal | JavaScript |
415+|---|---|
416+| `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.` | `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;` · ` };` · `},` · `[]);` |
890417
891418## Translating case..do
892419
893420Although 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.
894421
895-<thead>
896-
897-</thead>
898-<tbody>
899-
900-<code>Var</code><br />
901-<code>  i: integer;</code><br />
902-<code>Begin</code><br />
903-<code>  case i of</code><br />
904-<code>    1: ;</code><br />
905-<code>    2: i:=3;</code><br />
906-<code>  else</code><br />
907-<code>    i:=4;</code><br />
908-<code>  end;</code><br />
909-<code>End.</code></td>
910-
911-<code>["System"],</code><br />
912-<code>function(){</code><br />
913-<code>  var $mod = this;</code><br />
914-<code>  this.i = 0;</code><br />
915-<code>  $mod.$main=function(n){</code><br />
916-<code>    $tmp1 = $mod.i;</code><br />
917-<code>    if ($tmp1 == 1){</code><br />
918-<code>    } else if ($tmp1 == 2) {</code><br />
919-<code>      i=3;</code><br />
920-<code>    } else {</code><br />
921-<code>      i=4;</code><br />
922-<code>    }</code><br />
923-<code>  };</code><br />
924-<code>},</code><br />
925-<code>[]);</code></td>
926-
927-</tbody>
422+| Pascal | JavaScript |
423+|---|---|
424+| `Program MyModule;` · `Var` · ` i: integer;` · `Begin` · ` case i of` · ` 1: ;` · ` 2: i:=3;` · ` else` · ` i:=4;` · ` end;` · `End.` | `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;` · ` }` · ` };` · `},` · `[]);` |
928425
929426## Translating with..do
930427
931428JavaScript has a **with**, but it is slow and deprecated. Instead a temporary variable is used:
932429
933-<thead>
934-
935-</thead>
936-<tbody>
937-
938-<code>Interface</code><br />
939-<code>type</code><br />
940-<code>  TClassA = class</code><br />
941-<code>    i: integer;</code><br />
942-<code>  end;</code><br />
943-
944-<code>procedure DoIt;</code><br />
945-
946-<code>Implementation</code><br />
947-
948-<code>procedure DoIt;</code><br />
949-<code>begin</code><br />
950-<code>  with TClassA.Create do</code><br />
951-<code>    i:=3;</code><br />
952-<code>end;</code><br />
953-
954-<code>End.</code></td>
955-
956-<code>["System"],</code><br />
957-<code>function(){</code><br />
958-<code>  var $mod = this;</code><br />
959-<code>  rtl.createClass($mod, "TClassA", pas.System.TObject, function () {</code><br />
960-<code>    this.$init = function () {</code><br />
961-<code>      this.i = 0;</code><br />
962-<code>    };</code><br />
963-<code>  });</code><br />
964-<code>  this.DoIt = function(){</code><br />
965-<code>    var $with1 = $mod.TClassA.$create("Create");</code><br />
966-<code>    $with1.i = 3;</code><br />
967-<code>  };</code><br />
968-<code>},</code><br />
969-<code>[]);</code></td>
970-
971-</tbody>
430+| Pascal | JavaScript |
431+|---|---|
432+| `Unit MyModule;` · `Interface` · `type` · ` TClassA = class` · ` i: integer;` · ` end;` · · `procedure DoIt;` · · `Implementation` · · `procedure DoIt;` · `begin` · ` with TClassA.Create do` · ` i:=3;` · `end;` · · `End.` | `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;` · ` };` · `},` · `[]);` |
972433
973434Note: If the with-expression is already a local variable no new variable is created. This is Delphi/FPC compatible.
974435
975436## Translating enums
976437
977438Enum values are translated to numbers. The enum type is translated to an object containing a mapping from name to number and number to name.
978439
979-<thead>
980-
981-</thead>
982-<tbody>
983-
984-<code>Interface</code><br />
985-<code>type</code><br />
986-<code>  TMyEnum = (</code><br />
987-<code>    Red,</code><br />
988-<code>    Green,</code><br />
989-<code>    Blue);</code><br />
990-<code>var</code><br />
991-<code>  e: TMyEnum = Blue;</code><br />
992-
993-<code>procedure DoIt;</code><br />
994-
995-<code>Implementation</code><br />
996-
997-<code>procedure DoIt;</code><br />
998-<code>begin</code><br />
999-<code>  e := Green;</code><br />
1000-<code>end;</code><br />
1001-
1002-<code>End.</code></td>
1003-
1004-<code>["System"],</code><br />
1005-<code>function(){</code><br />
1006-<code>  var $mod = this;</code><br />
1007-<code>  this.TMyEnum = {</code><br />
1008-<code>    "0":"Red",</code><br />
1009-<code>    Red:0,</code><br />
1010-<code>    "1":"Green",</code><br />
1011-<code>    Green:1,</code><br />
1012-<code>    "2":"Blue",</code><br />
1013-<code>    Blue:2</code><br />
1014-<code>    };</code><br />
1015-<code>  this.e = $mod.TMyEnum.Blue;</code><br />
1016-<code>  this.DoIt = function(){</code><br />
1017-<code>    $mod.e = $mod.TMyEnum.Green;</code><br />
1018-<code>  };</code><br />
1019-<code>},</code><br />
1020-<code>[]);</code></td>
1021-
1022-</tbody>
440+| Pascal | JavaScript |
441+|---|---|
442+| `Unit MyModule;` · `Interface` · `type` · ` TMyEnum = (` · ` Red,` · ` Green,` · ` Blue);` · `var` · ` e: TMyEnum = Blue;` · · `procedure DoIt;` · · `Implementation` · · `procedure DoIt;` · `begin` · ` e := Green;` · `end;` · · `End.` | `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;` · ` };` · `},` · `[]);` |
1023443
1024444- Supported: ord(), low(), high(), pred(), succ(), type cast number to enum.
1025445- With optimization level -O1 the compiler uses numbers instead of names.
1026446- Not yet implemented: custom values for enum values.
1027447
1028448## Translating sets
1029449
1030450A set s is translated to a JavaScript object, where for each included enum holds *s.enumvalue==true*. This allows arbitrary large sets and the *in* operator is fast.
1031451
1032-<thead>
1033-
1034-</thead>
1035-<tbody>
1036-
1037-<code>Interface</code><br />
1038-<code>type</code><br />
1039-<code>  TColor = (Red, Green, Blue);</code><br />
1040-<code>  TColors = set of TColor;</code><br />
1041-
1042-<code>procedure DoIt;</code><br />
1043-
1044-<code>Implementation</code><br />
1045-
1046-<code>procedure DoIt;</code><br />
1047-<code>var</code><br />
1048-<code>  c: TColor;</code><br />
1049-<code>  S, T: TColors;</code><br />
1050-<code>  b: boolean;</code><br />
1051-<code>begin</code><br />
1052-<code>  S:=T;</code><br />
1053-<code>  b:=Red in S;</code><br />
1054-<code>  Include(S,Blue);</code><br />
1055-<code>  Exclude(S,Blue);</code><br />
1056-<code>  S:=S+T;</code><br />
1057-<code>  S:=S-[Red,c];</code><br />
1058-<code>  b:=c in [Red..Blue];</code><br />
1059-<code>end;</code><br />
1060-
1061-<code>End.</code></td>
1062-
1063-<code>["System"],</code><br />
1064-<code>function(){</code><br />
1065-<code>  var $mod = this;</code><br />
1066-<code>  this.TColor = {</code><br />
1067-<code>    "0":"Red",</code><br />
1068-<code>    Red:0,</code><br />
1069-<code>    "1":"Green",</code><br />
1070-<code>    Green:1,</code><br />
1071-<code>    "2":"Blue",</code><br />
1072-<code>    Blue:2</code><br />
1073-<code>    };</code><br />
1074-<code>  $mod.DoIt = function(){</code><br />
1075-<code>    var c = 0;</code><br />
1076-<code>    var S = {};</code><br />
1077-<code>    var T = {};</code><br />
1078-<code>    var b = false;</code><br />
1079-<code>    S = rtl.refSet(T);</code><br />
1080-<code>    b = $mod.TColor.Red in S;</code><br />
1081-<code>    S = rtl.includeSet(S,$mod.TColor.Blue);</code><br />
1082-<code>    S = rtl.excludeSet(S,$mod.TColor.Blue);</code><br />
1083-<code>    S = rtl.unionSet(S,T);</code><br />
1084-<code>    S = rtl.diffSet(S,rtl.createSet($mod.TColor.Red,c));</code><br />
1085-<code>    b = c in rtl.createSet(null,$mod.TColor.Red,$mod.TColor.Blue);</code><br />
1086-<code>  };</code><br />
1087-<code>},</code><br />
1088-<code>[]);</code></td>
1089-
1090-</tbody>
452+| Pascal | JavaScript |
453+|---|---|
454+| `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.` | `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);` · ` };` · `},` · `[]);` |
1091455
1092456- Supported:
1093457 - Include
1094458 - Exclude
1095459 - literal
1096460 - literal range, e.g. *\[EnumA..EnumB\], \['a'..'z'\]*
1097461 - union +
1098462 - difference -
1099463 - intersect *
1100464 - symmetrical difference \>\<
1101465 - equal =
1102466 - unequal \<\>
1103467 - subset \<=
1104468 - superset \>=
1105469 - set of anonymous enum type: *set of (enum1,enum2,...)*
1106470- Not supported: set of char, set of boolean
1107471- There is no optimization yet for small sets like in Delphi/FPC.
1108472- Assigning a set or passing the set as an argument only creates a reference and marks the set as *shared*. When a *shared* set is altered with Include/Exclude a new set is created (copy on write).
1109473- Passing a set as an argument might clone the set. Use the *const* modifier for parameters whenever possible.
1110474- Constant sets in expressions (e.g. *if c in \['a'..'z'\] then*) are not yet optimized and created every time. Create a *const* to avoid this.
1111475
1112476## Translating array type
1113477
1114478All arrays are translated into JavaScript arrays.\
1115479Contrary 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.
1116480
1117-<thead>
1118-
1119-</thead>
1120-<tbody>
1121-
1122-<code>Interface</code><br />
1123-<code>Type</code><br />
1124-<code>  TIntArr = Array of integer;</code><br />
1125-<code>  TObjArr = Array of TObject;</code><br />
1126-<code>  TRec = record c: char; end;</code><br />
1127-<code>  TRecArr = Array of TRec;</code><br />
1128-<code>Procedure Test;</code><br />
1129-<code>Implementation</code><br />
1130-<code>Procedure Test;</code><br />
1131-<code>Var</code><br />
1132-<code>  IntArr: TIntArr = (1,2,3);</code><br />
1133-<code>  ObjArr: TObjArr;</code><br />
1134-<code>  RecArr: TRecArr;</code><br />
1135-<code>Begin</code><br />
1136-<code>  IntArr:=nil;</code><br />
1137-<code>  SetLength(IntArr,4);</code><br />
1138-<code>  IntArr[2]:=2;</code><br />
1139-<code>  IntArr[1]:=length(IntArr);</code><br />
1140-<code>  SetLength(ObjArr,5);</code><br />
1141-<code>  SetLength(RecArr,2,TRec);</code><br />
1142-<code>End;</code><br />
1143-<code>End.</code></td>
1144-
1145-<code>["System"],</code><br />
1146-<code>function(){</code><br />
1147-<code>  var $mod = this;</code><br />
1148-<code>  this.Test = function(){</code><br />
1149-<code>    this.TRec = function(s){</code><br />
1150-<code>      if (s){</code><br />
1151-<code>        this.c = s.c;</code><br />
1152-<code>      } else {</code><br />
1153-<code>        this.c = "";</code><br />
1154-<code>      };</code><br />
1155-<code>      this.$equal = function(b){</code><br />
1156-<code>        return (this.c == b.c);</code><br />
1157-<code>      };</code><br />
1158-<code>    };</code><br />
1159-<code>    this.IntArr = [1,2,3];</code><br />
1160-<code>    this.ObjArr = [];</code><br />
1161-<code>    this.RecArr = [];</code><br />
1162-<code>    this.Test = function(){</code><br />
1163-<code>      $mod.IntArr = [];</code><br />
1164-<code>      rtl.arraySetLength($mod.IntArr,4,0);</code><br />
1165-<code>      $mod.IntArr[2] = 2;</code><br />
1166-<code>      $mod.IntArr[1] = $mod.IntArr.length;</code><br />
1167-<code>      rtl.setArrayLength($mod.ObjArr,5,null);</code><br />
1168-<code>      rtl.setArrayLength($mod.RecArr,2,$mod.TRec);</code><br />
1169-<code>    }</code><br />
1170-<code>  };</code><br />
1171-<code>},</code><br />
1172-<code>[]);</code></td>
1173-
1174-</tbody>
481+| Pascal | JavaScript |
482+|---|---|
483+| `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.` | `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);` · ` }` · ` };` · `},` · `[]);` |
1175484
1176485Notes:
1177486
1178487- Supported features of dynamic arrays: SetLength(), Length(), equal/notequal nil, low(), high(), assigned(), concat(), copy(), insert(), delete(), multi dimensional, array of record
1179488- Dynamic array constants. E.g. in mode ObjFPC *const a: array of byte = (1,2)*. In mode Delphi you must use square brackets, *... = \[1,2\]*
1180489- Supported features of static arrays: length(), low(), high(), assigned(), concat(), copy(), const, const records
1181490- Open arrays are implemented as dynamic arrays.
1182491- Calling *Concat()* with only one array simply returns the array (no cloning). Calling it with multiple arrays creates a clone. This is Delphi 10.1 compatible.
1183492- In Delphi/FPC an empty array is *nil*. In JS it can be *null* or *\[\]*. For compatibility comparing an array with *nil* checks for *length(a)\>0*.
1184493- *function Assigned(array): boolean* results true iff *length(array)\>0*.
1185494- array of const:
1186495 - Works the same: vtInteger, vtBoolean, vtPointer, vtObject, vtClass, vtWideChar, vtInterface, vtUnicodeString
1187496 - ''longword'' is converted to ''vtNativeInt''. Delphi/FPC converts to ''vtInteger'', changing big numbers to negative numbers.
1188497 - vtExtended is double, Delphi/FPC: PExtended
1189498 - vtCurrency is currency, Delphi/FPC: PCurrency
1190499 - Not supported: vtChar, vtString, vtPChar, vtPWideChar, vtAnsiString, vtVariant, vtWideString, vtInt64, vtQWord
1191500 - only in pas2js: vtNativeInt, vtJSValue
1192501- Assignation using constant array, e.g. *a:=\[1,1,2\];*
1193502- String like operation: + operator concatenates arrays. e.g. *a:=\[1\]+\[2\];*. This is controlled by modeswitch arrayoperators, which is enabled in mode delphi.
1194503- *function copy(array,start=0,count=max): array*
1195504- *procedure insert(item,var array,const position)*
1196505- *procedure delete(var array,const start,count)*
1197506
1198507## Translating class type
1199508
1200509Classes are implemented using *Object.create* and some rtl magic.
1201510
1202-<thead>
1203-
1204-</thead>
1205-<tbody>
1206-
1207-<code>Interface</code><br />
1208-<code>Type</code><br />
1209-<code>  TClassA = Class(TObject)</code><br />
1210-<code>  Public</code><br />
1211-<code>    i: integer;</code><br />
1212-<code>    Procedure Add(a: integer);</code><br />
1213-<code>  End;</code><br />
1214-<code>var</code><br />
1215-<code>  ObjA: TClassA;</code><br />
1216-<code>Implementation</code><br />
1217-<code>Procedure TClassA.Add(a: integer);</code><br />
1218-<code>Begin</code><br />
1219-<code>  i:=i+a;</code><br />
1220-<code>End;</code><br />
1221-<code>Initialization</code><br />
1222-<code>  ObjA:=TClassA.Create;</code><br />
1223-<code>End.</code></td>
1224-
1225-<code>["System"],</code><br />
1226-<code>function(){</code><br />
1227-<code>  var $mod = this;</code><br />
1228-<code>  rtl.createClass($mod,"TClassA",pas.System.TObject,function(){</code><br />
1229-<code>    this.$init = function () {</code><br />
1230-<code>      this.i = 0;</code><br />
1231-<code>    };</code><br />
1232-<code>    this.Add = function(a){</code><br />
1233-<code>      this.i = this.i + a;</code><br />
1234-<code>    };</code><br />
1235-<code>  });</code><br />
1236-<code>  this.ObjA = null;</code><br />
1237-<code>  $mod.$init = function(){</code><br />
1238-<code>    $mod.ObjA = $mod.TClassA.$create("Create");</code><br />
1239-<code>  };</code><br />
1240-<code>},</code><br />
1241-<code>[]);</code></td>
1242-
1243-</tbody>
511+| Pascal | JavaScript |
512+|---|---|
513+| `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.` | `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");` · ` };` · `},` · `[]);` |
1244514
1245515Notes:
1246516
1247517- Each class and each instance is an JS object.
1248518- Each class has a globally unique JS object, created by rtl.createClass.
1249519- *Self* is never *nil*.
1250520- The method *TObject.Free* is using compiler magic. See \[#tobjectfree Translating TObject.Free\].
1251521- *Class.\$class* is a reference to the class itself.
1252522- *Class.\$ancestor* is a reference to the ancestor class.
1253523- A class has *c.\$ancestor == Object.getPrototypeOf(c)*.
1254524- A class instance has *o.\$class == Object.getPrototypeOf(o)*.
1255525- *Class.\$classname* is the short name. E.g. *TClassA.\$classname == 'TClassA*'.
1256526- *Class.\$name* is the long name. E.g. *TClassA.\$name == 'MyModule.TClassA*'.
1257527- *Class.\$unitname* is the unit name. E.g. *TClassA.\$unitname == 'MyModule*'.
1258528- The "*is*"-operator is implemented using "*isPrototypeOf*". Note that "*instanceof*" cannot be used, because classes are JS objects.
1259529- The "*as*" operator is implemented as *rtl.as(Object,Class)*.
1260530- Supported:
1261531 - constructor, destructor
1262532 - private, protected, public, strict private, strict protected
1263533 - class vars, const, nested types
1264534 - methods, class methods, class constructor, external methods
1265535 - method modifiers overload, reintroduce, virtual, override, abstract, static, external name, message integer, message string
1266536 - call inherited
1267537 - assigned()
1268538 - type cast
1269539 - class sealed, class abstract
1270540- Not supported: class destructor
1271541- Property:
1272542 - References are replaced by getter/setter.
1273543 - Supported: argument lists, default property, class property, stored modifier, index modifier.
1274544 - Not supported: getter/setter to an array element, e.g. *property A: char read FArray\[0\];*
1275545 - Class property getter/setter can be static or non static. Delphi: must be static.
1276546 - The *Index* 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.
1277547
1278548## Translating class-of type
1279549
1280550A class-of is a reference to a class. See above about translating class.
1281551
1282-<thead>
1283-
1284-</thead>
1285-<tbody>
1286-
1287-<code>Interface</code><br />
1288-<code>Type</code><br />
1289-<code>  TBird = Class(TObject)</code><br />
1290-<code>  Public</code><br />
1291-<code>    Class var Count: integer;</code><br />
1292-<code>    Class Procedure Add(a: integer); virtual;</code><br />
1293-<code>  End;</code><br />
1294-<code>  TBirds = class of TBird;</code><br />
1295-
1296-<code>  TPigeon = Class(TBird)</code><br />
1297-<code>  Public</code><br />
1298-<code>    Class Procedure Add(a: integer); override;</code><br />
1299-<code>  End;</code><br />
1300-
1301-<code>var</code><br />
1302-<code>  BirdType: TBirds;</code><br />
1303-<code>Implementation</code><br />
1304-<code>Class Procedure TBird.Add(a: integer);</code><br />
1305-<code>Begin</code><br />
1306-<code>  Count:=Count+a;</code><br />
1307-<code>End;</code><br />
1308-<code>Class Procedure TPigeon.Add(a: integer);</code><br />
1309-<code>Begin</code><br />
1310-<code>  inherited Add(a+1);</code><br />
1311-<code>End;</code><br />
1312-<code>Initialization</code><br />
1313-<code>  BirdType:=TPigeon;</code><br />
1314-<code>  BirdType.Add(1);</code><br />
1315-<code>End.</code></td>
1316-
1317-<code>["System"],</code><br />
1318-<code>function(){</code><br />
1319-<code>  var $mod = this;</code><br />
1320-<code>  rtl.createClass($mod,"TBird",pas.System.TObject,function () {</code><br />
1321-<code>    this.Count = 0;</code><br />
1322-<code>    this.Add = function (a) {</code><br />
1323-<code>      this.Count = this.Count + a;</code><br />
1324-<code>    };</code><br />
1325-<code>  });</code><br />
1326-<code>  rtl.createClass($mod,"TPigeon",$mod.TBird,function () {</code><br />
1327-<code>    this.Add = function (a) {</code><br />
1328-<code>      $mod.TBird.Add.call(this,a + 1);</code><br />
1329-<code>    };</code><br />
1330-<code>  });</code><br />
1331-<code>  $mod.$init = function(){</code><br />
1332-<code>    $mod.BirdType = $mod.TPigeon;</code><br />
1333-<code>    $mod.BirdType.Add(1);</code><br />
1334-<code>  };</code><br />
1335-<code>},</code><br />
1336-<code>[]);</code></td>
1337-
1338-</tbody>
552+| Pascal | JavaScript |
553+|---|---|
554+| `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.` | `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);` · ` };` · `},` · `[]);` |
1339555
1340556Note that *this* in a class method is the class itself.\
1341557
1342558Notes:\
1343559
1344560- Contrary to Delphi/FPC the "is" operator works with class-of.
1345561
1346562## Translating TObject.Free
1347563
1348564In 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 *null*).\
1349565Therefore pas2js adds code to call the destructor and sets the variable to *nil*:\
1350566
1351567- *Obj.Free* on a local variable or argument is translated to *Obj = rtl.freeLoc(Obj);*.
1352568- *Obj.Free* on a non local variable is translated to *rtl.free(this,"Obj");*.
1353569- Not supported: Freeing a property or function result.\
1354570 For example *List\[i\].Free* gives a compiler error. The property setter might create side effects, which would be incompatible to Delphi/FPC.
1355571
1356572Notes:
1357573
1358574- If the destructor raises an exception, the variable is not set to *nil*. This is compatible to Delphi/FPC, where the memory is not freed in this case.
1359575- Alternatively you can use *FreeAndNil*, which first changes the variable to *nil* and then calls the destructor.
1360576
1361577## Translating class interfaces
1362578
1363579JavaScript has nothing like it, so they are emulated.\
1364580An 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:\
1365581
1366582`{`\
1367583`  $module: [object Object],`\
1368584`  $name: "IUnknown",`\
1369585`  $fullname: "System.IUnknown",`\
1370586`  $guid: "{00000000-0000-0000-C000-000000000046}",`\
1371587`  $names: ["QueryInterface","_AddRef","_Release"],`\
1372588`  $rtti: [object Object],`\
1373589`  $kind: "com",`\
1374590`}`
1375591
1376592A class implementing interfaces has a variable *\$intfmaps*, 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 *IUnknown* of *TInterfacedObject*:\
1377593
1378594`{`\
1379595`  QueryInterface: function (){ return fn.apply(this.$o,arguments); },`\
1380596`  _AddRef: function (){ return fn.apply(this.$o,arguments); },`\
1381597`  _Release: function (){ return fn.apply(this.$o,arguments); },`\
1382598`  ...`\
1383599`}`
1384600
1385601When an interface is created for an object (here: a Pascal class instance), for example by using the *as*-operator "*ObjVar as IUnknown*", a JS object is created, which is an instance of the map object with its *\$o* set to the *ObjVar*.\
1386602
1387603Supported:
1388604
1389605- methods, properties, default property
1390606- *{\$interfaces com\|corba\|default}*\
1391607 * 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
1392608 - CORBA: lightweight, no automatic reference counting, no default ancestor, fast support checks.
1393609- inheriting
1394610- An interface without a GUID gets one autogenerated from its name and method names.
1395611- Contrary to Delphi/FPC you can assign an interface type or var to the type TGuidString.
1396612- a class implementing an interface must not be external
1397613- 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.
1398614- method resolution, procedure IUnknown._AddRef = IncRef;
1399615- delegation: property Name: interface\|class read Field\|Getter implements AnInterface;
1400616- is-operator:
1401617 - IntfVar is IntfType - types must be releated
1402618 - IntfVar is ClassType - types can be unrelated, class must not be external
1403619 - ObjVar is IntfType - can be unrelated
1404620- as-operator
1405621 - IntfVar as IntfType - types must be releated
1406622 - IntfVar as ClassType - types can be unrelated, nil returns nil, invalid raises EInvalidCast
1407623 - ObjVar as IntfType - can be unrelated, nil if not found, COM: uses _AddRef
1408624- typecast:
1409625 - IntfType(IntfVar) - must be related
1410626 - ClassType(IntfVar) - can be unrelated, nil if invalid
1411627 - IntfType(ObjVar) - nil if not found, COM: if ObjVar has delegate uses _AddRef
1412628 - TJSObject(IntfTypeOrVar). Note that you cannot typecast directly to a *TJSObject* descendant. You can use *TJSWindow(TJSObject(IntfType))*.
1413629 - jsvalue(intfvar)
1414630- Assign operator:
1415631 - IntfVar:=nil;
1416632 - IntfVar:=IntfVar2; - IntfVar2 must be same type or a descendant
1417633 - IntfVar:=ObjVar; - nil if unsupported
1418634 - jsvalue:=IntfVar;
1419635 - TGUIDVar:=IntfType;
1420636 - TGUIDVar:=IntfVar;
1421637 - TGUIDVar:=stringconstant;
1422638 - TGUIDStringVar:=IntfVar;
1423639 - StringVar:=GuidVar;
1424640- Equal/Inequal operator:
1425641 - IntfVar=nil;
1426642 - IntfVar=IntfVar2; - must be related
1427643 - jsvalue=IntfVar;
1428644 - TGUIDVar=IntfType;
1429645 - TGUIDVar=IntfVar;
1430646 - TGUIDVar=string;
1431647 - TGUIDStringVar=IntfVar;
1432648- Passing an COMIntfVar to an untyped parameter or *JSValue* does not trigger *_AddRef, _Release*.
1433649- Assigned(IntfVar)
1434650- RTTI, typeinfo(IntfType), typeinfo(IntfVar)
1435651
1436652Not yet supported: array of intferfacetype, interface as record member.
1437653
1438654## Translating helpers
1439655
1440656Pas2js supports class helpers, record helpers and type helpers since 1.3. The extend is only virtual, the helped type is kept untouched.\
1441657
1442658- A **class helper** can "extend" Pascal classes and external JS classes.
1443659- A **record helper** can "extend" a record type. In \$mode delphi a record helper can extend other types as well, see *type helper*
1444660- A **type helper** 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.\
1445661 Type helpers are enabled by default in *\$mode delphi* and disabled in *\$mode objfpc*. You can enable them with **{\$modeswitch typehelpers}**.
1446662- 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.\
1447663 A class with ancestors can have one active helper per ancestor type, so multiple helpers can be active, same as FPC/Delphi.\
1448664 Using **{\$modeswitch multihelpers}** you can activate all helpers within scope.
1449665- Nested helpers (e.g. *TDemo.TSub.THelper*) are elevated. Visibility is ignored. Same as FPC/Delphi.
1450666- Helpers cannot be forward defined (e.g. no *THelper = helper;*).
1451667- Helpers must not have fields.
1452668- **Class Var, Const, Type**
1453669- **Visibility** : *strict private .. published*
1454670- **Function, procedure**: In class and record helpers *Self* is the class/record instance. For other types Self is a reference to the passed value.
1455671- **Class function, class procedure**: Helpers for Pascal classes/records can add *static* and non static class functions. Helpers for external classes and other types can only add static class functions.
1456672- **Constructor**. Not for external classes. Works similar to construcors, i.e. *THelpedClass.Create* creates a new instance, while *AnObj.Create* calls the constructor function as normal method. Note that Delphi does not allow calling helper construcors as normal method.
1457673- no destructor
1458674- **Property** : getters/setters can refer to members of the helper, its ancestors and the helped class/record.
1459675- **Class property** : getter can be static or non static. Delphi/FPC only allows static.
1460676- **Ancestors** : Helpers can have an ancestor helper, but they do not have a shared root class, especially not *TObject*.
1461677- **no virtual, abstract, override**. Delphi allows them, but 10.3 crashes when calling.
1462678- **inherited** : *inherited* inside a method of a class/record calls helper of ancestor.\
1463679 *inherited* inside a helper depends on the \$mode:
1464680 - *\$mode objfpc* : *inherited;* and *inherited Name(args);* work the same and searches first in HelperForType, then in ancestor(s).
1465681 - *\$mode delphi: inherited;* : skip ancestors and HelperForType, searches first in helper(s) of ancestor of HelperForType.
1466682 - *\$mode delphi: inherited name(args);* : same as \$mode objfpc first searches in HelperForType, then Ancestor(s) In any case if *inherited;* has no ancestor to call, it is silently ignored, while *inherited Name;* gives an error.
1467683- **RTTI**: *typeinfo(somehelper)* returns a pointer to *TTypeInfoHelper* with *Kind tkHelper*.
1468684- There are some special cases when using a **type helper** function/procedure on a value:
1469685 - *function result* : using a temporary variable
1470686 - *const, const argument* : When helper function tries to assign a value, pas2js raises a EPropReadOnly exception. FPC/Delphi use a temporary variable allowing the write.
1471687 - *property* : 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.
1472688 - *with value do ;* : uses a temporary variable. Delphi/FPC do not support it.
1473689- A method with *external name* modifier is treated as an external method of the helped type.
1474690
1475691## Translating attributes
1476692
1477693Attributes are stored in the TTypeInfo objects as streams stored in an array. See the function *GetRTTIAttributes* in unit *TypInfo* for details.
1478694
1479695## Translating try..finally
1480696
1481697JavaScript has the same, so it translates straight forward.
1482698
1483699## Translating try..except
1484700
1485-<thead>
1486-
1487-</thead>
1488-<tbody>
1489-
1490-<code>Interface</code><br />
1491-<code>Uses SysUtils, Math, JS;</code><br />
1492-<code>Function DoIt(n: integer): double;</code><br />
1493-<code>Implementation</code><br />
1494-<code>Function DoIt(n: integer): double;</code><br />
1495-<code>var E: Exception;</code><br />
1496-<code>Begin</code><br />
1497-<code>  try</code><br />
1498-<code>    Result:=double(7.0)/n;</code><br />
1499-<code>    if not IsFinite(Result) then</code><br />
1500-<code>      if n=0 then</code><br />
1501-<code>        raise EZeroDivide.Create</code><br />
1502-<code>      else</code><br />
1503-<code>        raise EOverflow.Create;</code><br />
1504-<code>  except</code><br />
1505-<code>    on EZeroDivide do Result:=0.0;</code><br />
1506-<code>    on E2: EOverflow do Result:=0.0;</code><br />
1507-<code>    else</code><br />
1508-<code>      raise EAbort.Create('Something other: '+String(JS.JSExceptObject));</code><br />
1509-<code>  end;</code><br />
1510-<code>End;</code><br />
1511-<code>End.</code></td>
1512-
1513-<code>["System","SysUtils"],</code><br />
1514-<code>function(){</code><br />
1515-<code>  this.DoIt=function(n){</code><br />
1516-<code>    Result = 0;</code><br />
1517-<code>    var E = null;</code><br />
1518-<code>    try{</code><br />
1519-<code>      Result = 7.0 / n;</code><br />
1520-<code>      if (!IsFinite(Result)){</code><br />
1521-<code>        if (n==0){</code><br />
1522-<code>          throw pas.SysUtils.EZeroDivide.$create("Create");</code><br />
1523-<code>        } else {</code><br />
1524-<code>          throw pas.SysUtils.EOverflow.$create("Create");</code><br />
1525-<code>        };</code><br />
1526-<code>      };</code><br />
1527-<code>    }catch($e){</code><br />
1528-<code>      if (pas.SysUtils.EZeroDivide.isPrototypeOf($e)){</code><br />
1529-<code>        Result = 0.0;</code><br />
1530-<code>      } else if (pas.SysUtils.EOverflow.isPrototypeOf($e)){</code><br />
1531-<code>        var E2 = $e;</code><br />
1532-<code>        Result = 0.0;</code><br />
1533-<code>      } else {</code><br />
1534-<code>        throw pas.SysUtils.EAbort.$create("Create",["Something other: "+(""+$e)]);</code><br />
1535-<code>      }</code><br />
1536-<code>    }</code><br />
1537-<code>    return Result;</code><br />
1538-<code>  };</code><br />
1539-<code>},</code><br />
1540-<code>[]);</code></td>
1541-
1542-</tbody>
701+| Pascal | JavaScript |
702+|---|---|
703+| `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.` | `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;` · ` };` · `},` · `[]);` |
1543704
1544705Notes:
1545706
1546707- Division by zero does not raise an exception in JavaScript. Instead it results in Infinity, except for 0/0 which results in NaN.
1547708- There is no ExceptObject in SysUtils.
1548709- When calling external functions keep in mind that JS allows to throw (raise) any value, often a string.\
1549710 You can access the current except value via JSExceptValue in unit JS.\
1550711 Note that this is only valid inside the catch-block. The compiler will not warn, if you use it outside.
1551712
1552713## Translating enumerators
1553714
1554715The for..in..do supports enumerating:
1555716
1556717- ordinal types like char, boolean, byte, ..., longword, enums, custom ranges are translated to a for loop.
1557718- set types are translated to a for loop, while const sets and set variables are enumerated via a for(...in...) loop.
1558719- string and array variables are enumerated via for loops.
1559720- for aString in ArrayOfString do ...
1560721- *for key in jsvalue do* translates to *for (key in jsvalue){}*
1561722- *for key in ExternalClass do*\
1562723 * If the externalclass has a ''length'' and a matching default property it uses the enumeration of an array. For example *for value in TJSArray do* enumerates the values of the array, not the index. It checks if the array is nil.
1563724 - Otherwise it translates to *for (key in externalclass){}*, which enumerates the keys (property names) of the JS object.
1564725
1565726The class GetEnumerator function is translated like this:
1566727
1567-<thead>
1568-
1569-</thead>
1570-<tbody>
1571-
1572-<code>Interface</code><br />
1573-
1574-<code>uses Classes;</code><br />
1575-
1576-<code>procedure DoIt(List: TList);</code><br />
1577-
1578-<code>Implementation</code><br />
1579-
1580-<code>procedure DoIt(List: TList);</code><br />
1581-<code>var</code><br />
1582-<code>  Item: Pointer;</code><br />
1583-<code>begin</code><br />
1584-<code>  for Item in List do</code><br />
1585-<code>    if Item&lt;&gt;nil then ;</code><br />
1586-<code>end;</code><br />
1587-
1588-<code>End.</code></td>
1589-
1590-<code>["System","Classes"],</code><br />
1591-<code>function(){</code><br />
1592-<code>  this.DoIt=function(List){</code><br />
1593-<code>    var Item = null;</code><br />
1594-<code>    var $in1 = List;</code><br />
1595-<code>    try {</code><br />
1596-<code>      while ($in1.MoveNext()) {</code><br />
1597-<code>        Item = $in1.GetCurrent();</code><br />
1598-<code>        if (Item !== null) ;</code><br />
1599-<code>      }</code><br />
1600-<code>    } finally {</code><br />
1601-<code>      $in1 = rtl.freeLoc($in1)</code><br />
1602-<code>    };</code><br />
1603-<code>  };</code><br />
1604-<code>},</code><br />
1605-<code>[]);</code></td>
1606-
1607-</tbody>
728+| Pascal | JavaScript |
729+|---|---|
730+| `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.` | `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)` · ` };` · ` };` · `},` · `[]);` |
1608731
1609732Notes:
1610733
1611734- Not supported: operator Enumerator, member modifier enumerator (i.e. custom Current and MoveNext)
1612735
1613736## Translating function types
1614737
1615738JavaScript 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 **this** to be the class or class instance.\
1616739Note that *bind* cannot be used, because it does not support the *equal* operator. Instead a wrapper is created:
1617740
1618-<thead>
1619-
1620-</thead>
1621-<tbody>
1622-
1623-<code>type</code><br />
1624-<code>  TMyMethod = procedure(n: integer) of object;</code><br />
1625-<code>  TBird = class</code><br />
1626-<code>    procedure DoIt(n: integer); virtual; abstract;</code><br />
1627-<code>  end;</code><br />
1628-<code>  TMyProc = procedure(n: integer);</code><br />
1629-<code>procedure DoSome(n: integer);</code><br />
1630-<code>begin</code><br />
1631-<code>end;</code><br />
1632-<code>var</code><br />
1633-<code>  m: TMyMethod;</code><br />
1634-<code>  Bird: TBird;</code><br />
1635-<code>  p: TMyProc;</code><br />
1636-<code>Begin</code><br />
1637-<code>  m:=@Bird.DoIt;</code><br />
1638-<code>  m(3);</code><br />
1639-<code>  p:=@DoSome;</code><br />
1640-<code>  p(4);</code><br />
1641-<code>End.</code></td>
1642-
1643-<code>["System","UnitA"],</code><br />
1644-<code>function(){</code><br />
1645-<code>  var $mod = this;</code><br />
1646-<code>  rtl.createClass($mod,"TBird",pas.System.TObject,function(){</code><br />
1647-<code>    this.DoIt = function (n) {</code><br />
1648-<code>    };</code><br />
1649-<code>  });</code><br />
1650-<code>  this.DoSome = function (n) {</code><br />
1651-<code>  };</code><br />
1652-<code>  this.m = null;</code><br />
1653-<code>  this.Bird = null;</code><br />
1654-<code>  this.p = null;</code><br />
1655-<code>  $mod.$main = function() {</code><br />
1656-<code>    $mod.m = rtl.createCallback($mod.Bird,"DoIt");</code><br />
1657-<code>    $mod.m(3);</code><br />
1658-<code>    $mod.p = $mod.DoSome;</code><br />
1659-<code>    $mod.p(4);</code><br />
1660-<code>  };</code><br />
1661-<code>},</code><br />
1662-<code>[]);</code><br />
1663-
1664-<code>rtl = {</code><br />
1665-<code>  ...</code><br />
1666-<code>  createCallback: function(scope, fn){</code><br />
1667-<code>    var cb;</code><br />
1668-<code>    if (typeof(fn)==='string'){</code><br />
1669-<code>      cb = function(){</code><br />
1670-<code>        return scope[fn].apply(scope,arguments);</code><br />
1671-<code>      };</code><br />
1672-<code>    } else {</code><br />
1673-<code>      cb = function(){</code><br />
1674-<code>        return fn.apply(scope,arguments);</code><br />
1675-<code>      };</code><br />
1676-<code>    };</code><br />
1677-<code>    cb.scope = scope;</code><br />
1678-<code>    cb.fn = fn;</code><br />
1679-<code>    return cb;</code><br />
1680-<code>  },</code><br />
1681-<code>  ...</code></td>
1682-
1683-</tbody>
741+| Pascal | JavaScript |
742+|---|---|
743+| `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:=@Bird.DoIt;` · ` m(3);` · ` p:=@DoSome;` · ` p(4);` · `End.` | `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;` · ` },` · ` ...` |
1684744
1685745Notes:
1686746
1687747- You can assign a nested procedure to procedure variable. You don't need and you must not add the FPC "*is nested*" modifier.
1688748- In pas2js a procedural typed declared as **reference to** accepts procedures, local procedures and methods. Delphi only supports capturing procedures and methods. FPC 3.0.4 does not support reference-to.
1689749- In pas2js the calling convention *safecall* has a special meaning:\
1690750 Assigning a procedure/method, uses *rtl.createSafeCallback* instead of *createCallback*, enclosing a call in a *try..catch* block. When an exception is thrown by JS, it is caught and delegated to *rtl.handleUncaughtException(err)*.\
1691751 For example:\
1692752 *aButtonElement.OnClick:=@DoClick;* uses *rtl.createSafeCallback*\
1693753 *aButtonElement.OnClick:=SomeElement.OnClick;* does not.\
1694754
1695755## Translating anonymous functions
1696756
1697757Anonymous functions are supported since pas2js 1.1.\
1698758Note that in pas2js local procedures are closures as well. See below.\
1699759For pas2js 1.0 the next best thing are local procedures. For example:
1700760
1701-<thead>
1702-
1703-</thead>
1704-<tbody>
1705-
1706-<code>type</code><br />
1707-<code>  TAdder = reference to function(n: integer): integer;</code><br />
1708-
1709-<code>function CreateAdder(a: integer): TAdder;</code><br />
1710-<code>begin</code><br />
1711-<code>  Result:=function(b: integer)</code><br />
1712-<code>    begin</code><br />
1713-<code>      Result:=a+b;</code><br />
1714-<code>    end;</code><br />
1715-<code>end;</code><br />
1716-
1717-<code>var</code><br />
1718-<code>  Adder: TAdder;</code><br />
1719-<code>Begin</code><br />
1720-<code>  Adder:=CreateAdder(3);</code><br />
1721-<code>  writeln(Adder(5)); // gives 8</code><br />
1722-<code>End.</code></td>
1723-
1724-<code>type</code><br />
1725-<code>  TAdder = reference to function(n: integer): integer;</code><br />
1726-
1727-<code>function CreateAdder(a: integer): TAdder;</code><br />
1728-<code>  function Add(b: integer): integer;</code><br />
1729-<code>  begin</code><br />
1730-<code>    Result:=a+b;</code><br />
1731-<code>  end;</code><br />
1732-<code>begin</code><br />
1733-<code>  Result:=@Add;</code><br />
1734-<code>end;</code><br />
1735-
1736-<code>var</code><br />
1737-<code>  Adder: TAdder;</code><br />
1738-<code>Begin</code><br />
1739-<code>  Adder:=CreateAdder(3);</code><br />
1740-<code>  writeln(Adder(5)); // gives 8</code><br />
1741-<code>End.</code></td>
1742-
1743-</tbody>
761+| Delphi | Pas2js |
762+|---|---|
763+| `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.` | `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.` |
1744764
1745765## Translating var modifier absolute
1746766
1747767The 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. *var r: TPoint absolute MyLongInt*).\
1748768The modifier is currently only supported for local variables.
1749769
1750770## Translating assert()
1751771
1752772The Assert(boolean\[,string\]) function is translated to *if(bool) throw x*. If unit sysutils is used, it creates an EAssertFailed exception.\
1753773Otherwise it throws a string.\
1754774
1755775- Command line enable with -Sa, disable with -Sa-
1756776- In code enable with *{\$C+}* or *{\$Assertions on}*, disable with *{\$C-}* or *{\$Assertions off}*
1757777
1758778## Dispatch messages
1759779
1760780The procedure modifier **message** and the **Dispatch** method works similar to FPC/Delphi, as it expects a record of a specific format and ***TObject.Dispatch*** calls the corresponding method with that message number or string.\
1761781The procedure modifier *message \<integer\>* adds an entry to hidden *YourClass.\$msgint* object, while the modifier *message \<string\>* adds an entry to the hidden *YourClass.\$msgstr* object.\
1762782Two new directives ***{\$DispatchField fieldname}**'' and***{\$DispatchStrField fieldname}**'' 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:
1763783
1764784`  {$DispatchField Msg} // enable checking message methods for record field name "Msg"`\
1765785`  {$DispatchStrField MsgStr}`\
1766786`  TObject = class`\
1767787`    procedure Dispatch(var aMessage); virtual;`\
1768788`    procedure DispatchStr(var aMessage); virtual;`\
1769789`  end;`\
1770790`  TMouseDownMsg = record`\
1771791`    Id: integer; // Id instead of Msg, works in FPC, but not in pas2js`\
1772792`    x,y: integer;`\
1773793`  end;`\
1774794`  TMouseUpMsg = record`\
1775795`    MsgStr: string;`\
1776796`    X,Y: integer;`\
1777797`  end;`\
1778798`  TWinControl = class`\
1779799`    procedure MouseDownMsg(var Msg: TMouseDownMsg); message 3; // warning: Dispatch requires record field Msg`\
1780800`    procedure MouseUpMsg(var Msg: TMouseUpMsg); message 'up'; // ok, record with string field name MsgStr`\
1781801`  end;`
1782802
1783803Note that descendant classes can override the *\$DispatchField* or disable the check using *{\$DispatchField -}*.
1784804
1785805## Calling JavaScript from Pascal
1786806
1787807Pas2js allows to write low level functions and/or access a JavaScript library with the following possibilities:
1788808
1789809## The asm block
1790810
1791811The asm block is pure JavaScript, that is copied directly into the generated .js file.
1792812
1793-<thead>
1794-
1795-</thead>
1796-<tbody>
1797-
1798-<code>var</code><br />
1799-<code>  s: string;</code><br />
1800-<code>Begin</code><br />
1801-<code>  s = 'Hello World!';</code><br />
1802-<code>  Asm</code><br />
1803-<code>    console.log(s);</code><br />
1804-<code>  End;</code><br />
1805-<code>End.</code></td>
1806-
1807-<code> ["System"],</code><br />
1808-<code> function(){</code><br />
1809-<code>   var $mod = this;</code><br />
1810-<code>   this.s = '';</code><br />
1811-<code>   $mod.$main = function(){</code><br />
1812-<code>     $mod.s = "Hello World!";</code><br />
1813-<code>     console.log(s);</code><br />
1814-<code>   };</code><br />
1815-<code> },</code><br />
1816-<code> []);</code><br />
1817-<code> </code></td>
1818-
1819-</tbody>
813+| Pascal | JavaScript |
814+|---|---|
815+| `Program MyModule;` · `var` · ` s: string;` · `Begin` · ` s = 'Hello World!';` · ` Asm` · ` console.log(s);` · ` End;` · `End.` | `rtl.module("program",` · ` ["System"],` · ` function(){` · ` var $mod = this;` · ` this.s = '';` · ` $mod.$main = function(){` · ` $mod.s = "Hello World!";` · ` console.log(s);` · ` };` · ` },` · ` []);` · ` ` |
1820816
1821817Notes:
1822818
1823819- 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.
1824820- The compiler does neither parse, nor check the syntax of the JS.
1825821- 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 *if MyVar=0 then;*
1826822- Accessing an interface, program or library identifier:\
1827823 * From inside the module you can use *\$mod.Identifier*.
1828824 - Otherwise use the fully qualified path *pas.Unitname.Identifier*.
1829825- Accessing an implementation identifier:\
1830826 * From inside the unit you can use *\$impl.Identifier*.
1831827 - Otherwise use the path *pas.Unitname.\$impl.Identifier*.
1832828- Accessing a class instance member (field, procedure, function, constructor, destructor) from a method of the class: use *this.Identifier*. Inside a nested function of a method you use the *Self.Identifier*.
1833829- Accessing a class member (class var, class procedure, class function) from a method of the class: for writing use *this.\$class.Identifier*, for reading you can omit the *\$class*.
1834830- Accessing a class member (class var, class procedure, class function) from a class method of the class: use *this.Identifier*.
1835831- Access to Properties must use the getter/setter.
1836832- When calling a Pascal method, make sure the **this** is correct:
1837833 - A class method (e.g. *class function*, *class procedure*) needs the class as *this*.\
1838834 **Wrong**: *aCar.DoIt(params,...)*\
1839835 **Correct**: *aCar.\$class.DoIt(params,...)*\
1840836- 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 *onclick* property. This will call the function with *this* set to the DOM element.\
1841837 Pascal methods needs a wrapper to set *this* to the instance. Examples:
1842838 - An unit function: *DOMElement.onclick = \$mod.DoIt;*
1843839 - An implementation function: *DOMElement.onclick = \$impl.DoIt;*.
1844840 - A method: *DOMElement.onclick = this.DoIt.bind(this);*
1845841 - A class function/procedure: *DOMElement.onclick = this.DoIt.bind(this.\$class);*
1846842 - A nested function: *DOMElement.onclick = DoIt;*.
1847843
1848844## The procedure modifier assembler
1849845
1850846You can write pure JavaScript functions like this:
1851847
1852-<thead>
1853-
1854-</thead>
1855-<tbody>
1856-
1857-<code>Procedure Log(const s: string); assembler;</code><br />
1858-<code>Asm</code><br />
1859-<code>  console.log(s);</code><br />
1860-<code>end;</code><br />
1861-
1862-<code>Begin</code><br />
1863-<code>  Log('Hello World!');</code><br />
1864-<code>End.</code></td>
1865-
1866-<code>["System"],</code><br />
1867-<code>function(){</code><br />
1868-<code>  var $mod = this;</code><br />
1869-<code>  this.Log = function(s){</code><br />
1870-<code>    console.log(s);</code><br />
1871-<code>  };</code><br />
1872-<code>  $mod.$main = function(){</code><br />
1873-<code>    $mod.Log("Hello World!");</code><br />
1874-<code>  };</code><br />
1875-<code>},</code><br />
1876-<code>[]);</code></td>
1877-
1878-</tbody>
848+| Pascal | JavaScript |
849+|---|---|
850+| `Program MyModule;` · · `Procedure Log(const s: string); assembler;` · `Asm` · ` console.log(s);` · `end;` · · `Begin` · ` Log('Hello World!');` · `End.` | `rtl.module("program",` · `["System"],` · `function(){` · ` var $mod = this;` · ` this.Log = function(s){` · ` console.log(s);` · ` };` · ` $mod.$main = function(){` · ` $mod.Log("Hello World!");` · ` };` · `},` · `[]);` |
1879851
1880852See also \[#asm asm\].
1881853
1882854## The procedure modifier external
1883855
1884856The procedure modifier *external* requires a string constant and tells the compiler to replace a reference with this string value. The value is not checked for JS syntax.
1885857
1886-<thead>
1887-
1888-</thead>
1889-<tbody>
1890-
1891-<code>Procedure ConsoleLog(const s: string); external name 'console.log';</code><br />
1892-<code>// Note: an external procedure has no begin..end block</code><br />
1893-<code>Begin</code><br />
1894-<code>  ConsoleLog('Hello World!');</code><br />
1895-<code>End.</code></td>
1896-
1897-<code>["System"],</code><br />
1898-<code>function(){</code><br />
1899-<code>  var $mod = this;</code><br />
1900-<code>  $mod.$main = function(){</code><br />
1901-<code>    console.log("Hello World!");</code><br />
1902-<code>  };</code><br />
1903-<code>},</code><br />
1904-<code>[]);</code></td>
1905-
1906-</tbody>
858+| Pascal | JavaScript |
859+|---|---|
860+| `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.` | `rtl.module("program",` · `["System"],` · `function(){` · ` var $mod = this;` · ` $mod.$main = function(){` · ` console.log("Hello World!");` · ` };` · `},` · `[]);` |
1907861
1908862## The procedure modifier varargs
1909863
1910864Appending the **varargs** 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 **varargs of aType** to allow only specific types.\
1911865To access these arguments use either *JSArguments* from unit JS or an *asm..end* block.
1912866
1913-<thead>
1914-
1915-</thead>
1916-<tbody>
1917-
1918-<code>uses JS;</code><br />
1919-<code>function Sum(b: boolean): longint; varargs;</code><br />
1920-<code>var i: longint;</code><br />
1921-<code>begin</code><br />
1922-<code>  if b then</code><br />
1923-<code>    asm</code><br />
1924-<code>      for (var i=0; i&lt;arguments.length; i++) Result+=arguments[i];</code><br />
1925-<code>    end</code><br />
1926-<code>  else</code><br />
1927-<code>    for i:=0 to JSArguments.length-1 do</code><br />
1928-<code>      Result:=Result+longint(JSArguments[i]);</code><br />
1929-<code>end;</code><br />
1930-<code>var</code><br />
1931-<code>  i: integer;</code><br />
1932-<code>Begin</code><br />
1933-<code>  i:=Sum(true,2,4,6); // i=12</code><br />
1934-<code>  i:=Sum(false,2,4,6); // i=12</code><br />
1935-<code>End.</code></td>
1936-
1937-<code>["System","JS"],</code><br />
1938-<code>function(){</code><br />
1939-<code>  var $mod = this;</code><br />
1940-<code>  this.Sum = function(b){</code><br />
1941-<code>    var Result = 0;</code><br />
1942-<code>    var i = 0;</code><br />
1943-<code>    if (b){</code><br />
1944-<code>      for (var i=0; i&lt;arguments.length; i++) Result+=arguments[i];</code><br />
1945-<code>    } else {</code><br />
1946-<code>      for (var $l1 = 1, $le2 = argumens.length; $l1 &lt;= $le2; $l1++){</code><br />
1947-<code>        $i = $l1;</code><br />
1948-<code>        Result = Result + arguments[i];</code><br />
1949-<code>      }</code><br />
1950-<code>    }</code><br />
1951-<code>    return Result;</code><br />
1952-<code>  };</code><br />
1953-<code>  this.i = 0;</code><br />
1954-<code>  $mod.$main = function(){</code><br />
1955-<code>    $mod.i = $mod.Sum(true,2,4,6);</code><br />
1956-<code>    $mod.i = $mod.Sum(false,2,4,6);</code><br />
1957-<code>  };</code><br />
1958-<code>},</code><br />
1959-<code>[]);</code></td>
1960-
1961-</tbody>
867+| Pascal | JavaScript |
868+|---|---|
869+| `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.` | `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);` · ` };` · `},` · `[]);` |
1962870
1963871The above example defines a function *Sum*, 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.
1964872
1965873## The var modifier external
1966874
1967875The var modifier *external* allows to use a JavaScript variable or constant.
1968876
1969-<thead>
1970-
1971-</thead>
1972-<tbody>
1973-
1974-<code>var</code><br />
1975-<code>  EulersNumber: Double; external name 'Math.E';</code><br />
1976-<code>  d: double;</code><br />
1977-<code>Begin</code><br />
1978-<code>  d:=EulersNumber;</code><br />
1979-<code>End.</code></td>
1980-
1981-<code>["System"],</code><br />
1982-<code>function(){</code><br />
1983-<code>  var $mod = this;</code><br />
1984-<code>  this.d = 0.0;</code><br />
1985-<code>  $mod.$main = function(){</code><br />
1986-<code>    $mod.d = Math.E;</code><br />
1987-<code>  };</code><br />
1988-<code>},</code><br />
1989-<code>[]);</code></td>
1990-
1991-</tbody>
877+| Pascal | JavaScript |
878+|---|---|
879+| `Program MyModule;` · `var` · ` EulersNumber: Double; external name 'Math.E';` · ` d: double;` · `Begin` · ` d:=EulersNumber;` · `End.` | `rtl.module("program",` · `["System"],` · `function(){` · ` var $mod = this;` · ` this.d = 0.0;` · ` $mod.$main = function(){` · ` $mod.d = Math.E;` · ` };` · `},` · `[]);` |
1992880
1993881## The external modifier of class members
1994882
1995883The method modifier *external* works as the procedure modifier, except it uses the scope of the class or instance.\
1996884The field modifier *external* works as the var modifier, except it uses the scope of the class or instance.\
1997885Requires the modeswitch **externalclass**.
1998886
1999-<thead>
2000-
2001-</thead>
2002-<tbody>
2003-
2004-<code>{$modeswitch externalclass}</code><br />
2005-<code>type</code><br />
2006-<code>  TWrapper = class</code><br />
2007-<code>  private</code><br />
2008-<code>    // let's assume this object has the properties "$Handle", "$id", and "0"</code><br />
2009-<code>  public</code><br />
2010-<code>    Id: NativeInt; external name '$Id';</code><br />
2011-<code>    x: NativeInt; external name '[0]';</code><br />
2012-<code>    y: NativeInt; external name '["A B"]';</code><br />
2013-<code>    function GetState(typ: longint): NativeInt; external name '$Handle.GetState';</code><br />
2014-<code>    procedure DoIt;</code><br />
2015-<code>  end;</code><br />
2016-<code>procedure TWrapper.DoIt;</code><br />
2017-<code>begin</code><br />
2018-<code>  Id := GetState(4);</code><br />
2019-<code>end;</code><br />
2020-<code>var</code><br />
2021-<code>  W: TWrapper;</code><br />
2022-<code>Begin</code><br />
2023-<code>  W.Id := 2;</code><br />
2024-<code>  W.x := 3;</code><br />
2025-<code>  W.y := 4;</code><br />
2026-<code>  W.GetState(5);</code><br />
2027-<code>End.</code></td>
2028-
2029-<code>["System"],</code><br />
2030-<code>function(){</code><br />
2031-<code>  var $mod = this;</code><br />
2032-<code>  rtl.createClass($mod, "TWrapper", pas.System.TObject, function () {</code><br />
2033-<code>    this.DoIt = function(){</code><br />
2034-<code>      this.$Id = this.$Handle.GetState(4);</code><br />
2035-<code>    };</code><br />
2036-<code>  });</code><br />
2037-<code>  this.W = null;</code><br />
2038-<code>  $mod.$main = function(){</code><br />
2039-<code>    $mod.W.$Id = 2;</code><br />
2040-<code>    $mod.W[0] = 3;</code><br />
2041-<code>    $mod.W["A B"] = 4;</code><br />
2042-<code>    $mod.W.$Handle.GetState(5);</code><br />
2043-<code>  };</code><br />
2044-<code>},</code><br />
2045-<code>[]);</code></td>
2046-
2047-</tbody>
887+| Pascal | JavaScript |
888+|---|---|
889+| `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.` | `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);` · ` };` · `},` · `[]);` |
2048890
2049891- Non identifiers like "0" or "A B" must be enclosed in brackets.
2050892
2051893## External classes
2052894
2053895pas2js introduces a new class modifier "*external name*", which makes the whole class external. External classes allow to easily declare Pascal wrappers for JavaScript objects and function objects.\
2054896They need the modeswitch **externalclass** in front of the class.\
2055897An external class is not a TObject and has none of its methods.\
2056898All members are external. If you omit the *external* modifier the external name is the member name. Keep in mind that JS is case sensitive.\
2057899Properties work the same as with Pascal classes, i.e. are replaced by Getter/Setter.\
2058900Destructors are not allowed.\
2059901Constructors are supported in four ways:
2060902
2061903- *constructor New* is translated to *new ExtClass(params)*, and for nested external class: *new ExtParentClass.ExtClass(Params)*
2062904- *constructor New; external name ''GlobalFunc''* is translated to *new GlobalFunc(params)*.
2063905- *constructor SomeName; external name*'{}' is translated to *{}*.
2064906- Otherwise it is translated to *new ExtClass.FuncName(params)*, and for nested external class: *new ExtParentClass.ExtClass.FuncName(params)*.
2065907
2066-<thead>
2067-
2068-</thead>
2069-<tbody>
2070-
2071-<code>{$modeswitch externalclass}</code><br />
2072-<code>type</code><br />
2073-<code>  TJSDate = class external name 'Date'</code><br />
2074-<code>  private</code><br />
2075-<code>    function getYear: NativeInt;</code><br />
2076-<code>    procedure setYear(const AValue: NativeInt);</code><br />
2077-<code>  public</code><br />
2078-<code>    constructor New;</code><br />
2079-<code>    constructor New(const MilliSecsSince1970: NativeInt);</code><br />
2080-<code>    class function now: NativeInt;</code><br />
2081-<code>    property Year: NativeInt read getYear write setYear;</code><br />
2082-<code>  end;</code><br />
2083-<code>var</code><br />
2084-<code>  d: TJSDate;</code><br />
2085-<code>Begin</code><br />
2086-<code>  d:=TJSDate.New;</code><br />
2087-<code>  d.Year:=d.Year+1;</code><br />
2088-<code>End.</code></td>
2089-
2090-<code>  var $mod = this;</code><br />
2091-<code>  this.d = null;</code><br />
2092-<code>  $mod.$main = function () {</code><br />
2093-<code>    $mod.d = new Date();</code><br />
2094-<code>    $mod.d.setYear($mod.d.getYear() + 1);</code><br />
2095-<code>  };</code><br />
2096-<code>});</code></td>
2097-
2098-</tbody>
908+| Pascal | JavaScript |
909+|---|---|
910+| `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.` | `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);` · ` };` · `});` |
2099911
2100912Notes:
2101913
2102914- An external class can descend from another external class.
2103915- Any class instance can be type casted to any root class.
2104916- A Pascal class can descend from an external class.
2105917- You can define a class-of external class and the **is** and **as** operators work similar.
2106918- Class variables work as in JavaScript. That means, each descendant and each instance can have its own value. For example *TExtA.Value* might be different from *InstanceExtA.Value*. Setting *InstanceExtA.Value* does not change *TExtA.Value*.
2107919- Const with an expression are replaced by the expression.
2108920- Const without an expression are treated as a readonly variable.
2109921- Class functions and class procedures are allowed, but can only be called via the class, not via an instance.\
2110922 For example you can call the class function *TJSString.fromCharCode()*, but you cannot call *aJSString.fromCharCode()*.
2111923- Since class types are JS objects it is possible to typecast a class type to the JS Object, e.g. *TJSObject(TObject)*. Note that you cannot typecast directly to a *TJSObject* descendant in \$mode objfpc. You can use *TJSWindow(TJSObject(ExtClassInstance))*.
2112924- You can typecast function addresses and function references to JS function, e.g. *TJSFunction(@SomeProc)*, *TJSFunction(OnClick)*. Keep in mind that typecasting a method address creates a function wrapper to bind the Self argument, except when typecasting to *TJSFunction* (pas2js 1.5+).
2113925
2114926## External class as ancestor
2115927
2116928A Pascal class can descend from an external class - a JS object or function.\
2117929The methods *AfterConstruction* and *BeforeDestruction* are called if they exist.\
2118930New instances of a JS Object descendant are created by default with *Object.create(ancestorclass)*.\
2119931New instances of a JS Function descendant are created by default with *new DescendantFunc()*.\
2120932You can override this, by providing a non private\
2121933**class function NewInstance(fnname: string; const paramsarray): TPasClass; virtual;**. 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.\
2122934
2123-<thead>
2124-
2125-</thead>
2126-<tbody>
2127-
2128-<code>Program MyModule;</code><br />
2129-<code>{$modeswitch externalclass}</code><br />
2130-<code>type</code><br />
2131-<code>  TExtA = class external name 'ExtA'</code><br />
2132-<code>  end;</code><br />
2133-<code>  TMyB = class(TExtA)</code><br />
2134-<code>  protected</code><br />
2135-<code>    // optional: override default allocation</code><br />
2136-<code>    class function NewInstance(fnname: string; const paramarray): TMyB; virtual;</code><br />
2137-<code>  end;</code><br />
2138-<code>class function TMyB.NewInstance(fnname: string; const paramarray): TMyB;</code><br />
2139-<code>Begin</code><br />
2140-<code>  asm</code><br />
2141-<code>  Result = Object.create(ExtA); // that is what the rtl does</code><br />
2142-<code>  end;</code><br />
2143-<code>End;</code><br />
2144-
2145-<code>Begin</code><br />
2146-<code>End.</code></td>
2147-
2148-<code>  var $mod = this;</code><br />
2149-<code>  rtl.createClassExt($mod, "TMyB", ExtA, "NewInstance", function () {</code><br />
2150-<code>    this.$init = function () {</code><br />
2151-<code>    };</code><br />
2152-<code>    this.$final = function () {</code><br />
2153-<code>    };</code><br />
2154-<code>    this.NewInstance = function (fnname, paramarray) {</code><br />
2155-<code>      var Result = null;</code><br />
2156-<code>      Result = Object.create(ExtA);</code><br />
2157-<code>      return Result;</code><br />
2158-<code>    };</code><br />
2159-<code>  });</code><br />
2160-<code>  $mod.$main = function () {</code><br />
2161-<code>  };</code><br />
2162-<code>});</code></td>
2163-
2164-</tbody>
2165-
2166-<thead>
2167-
2168-</thead>
2169-<tbody>
2170-
2171-<code>Program MyModule;</code><br />
2172-<code>{$modeswitch externalclass}</code><br />
2173-<code>uses JS;</code><br />
2174-<code>type</code><br />
2175-<code>  TExternalFunc = class external name 'ExternalFunc'(TJSFunction)</code><br />
2176-<code>    constructor New(a: word);</code><br />
2177-<code>  end;</code><br />
2178-<code>  TMyFunc = class(TExternalFunc)</code><br />
2179-<code>    constructor Create(b: word);</code><br />
2180-<code>  end;</code><br />
2181-<code>constructor TMyFunc.Create(b: word);</code><br />
2182-<code>Begin</code><br />
2183-<code>  inherited New(b+1); // optional: call inherited constructor function</code><br />
2184-<code>End;</code><br />
2185-
2186-<code>var</code><br />
2187-<code>  f: TMyFunc;</code><br />
2188-<code>Begin</code><br />
2189-<code>  f:=TMyFunc.Create(3);</code><br />
2190-<code>  writeln(jsInstanceOf(f,TExternalFunc)); // writes true, instanceof operator works as expected</code><br />
2191-<code>End.</code></td>
2192-
2193-<code>  var $mod = this;</code><br />
2194-<code>  rtl.createClassExt($mod, "TMyFunc", ExternalFunc, "", function () {</code><br />
2195-<code>    this.$init = function () {</code><br />
2196-<code>    };</code><br />
2197-<code>    this.$final = function () {</code><br />
2198-<code>    };</code><br />
2199-<code>    this.Create$2 = function (b) {</code><br />
2200-<code>      this.$ancestorfunc(b+1);</code><br />
2201-<code>    };</code><br />
2202-<code>  });</code><br />
2203-<code>  this.f = null;</code><br />
2204-<code>  $mod.$main = function () {</code><br />
2205-<code>    f = $mod.TMyFunc.$create("Create$2",[3]);</code><br />
2206-<code>    pas.System.Writeln(pas.JS.jsInstanceOf(f,ExternalFunc));</code><br />
2207-<code>  };</code><br />
2208-<code>});</code></td>
935+| Pascal | JavaScript |
936+|---|---|
937+| `// 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.` | `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 () {` · ` };` · `});` |
2209938
2210-</tbody>
939+| Pascal | JavaScript |
940+|---|---|
941+| `// 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.` | `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));` · ` };` · `});` |
2211942
2212943## The JSValue type
2213944
2214945Pas2js introduces a new type **JSValue**, 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.\
2215946Key features:\
2216947
2217948- A JSValue variable initial value is undefined.
2218949- Operators: =, \<\>
2219950- type casting a *JSValue* to ...
2220951 - *Integer: Math.floor(aJSValue)* Note: may return *NaN*
2221952 - *Boolean: !(aJSValue == false)* Note: works for numbers too, *0==false*
2222953 - *Double: rtl.getNumber(aJSValue)* Note: *typeof(n)=="number"?n:NaN;*
2223954 - *String: ""+aJSValue*
2224955 - *Char: rtl.getChar(aJSValue)* Note: *((typeof(c)!="string") && (c.length==1)) ? c : ""*
2225956 - class instance or class-of: *rtl.getObject()* Note: checks for type *"object"*
2226957 - enum type
2227958 - pointer
2228959- A JSValue in a conditional expressions *If aJSValue then, while aJSValue do, repeat until aJSValue* has the same meaning as in JS: the condition is true, if the value is not *undefined, false, null, NaN, 0, ''*. Note that *new Boolean(false)* is not *null* and the condition is true.
2229960- *function Assigned(V: jsvalue): boolean* returns true if\
2230961 *(V!=undefined) && (V!=null) && (!rtl.isArray(V) \|\| (V.length \> 0))*
2231962- *function StrictEqual(const A: jsvalue; const B): boolean*
2232963- *function StrictInequal(const A: jsvalue; const B): boolean*
2233964- Any array can be assigned to an *array of jsvalue*.
2234965- is-operator: *jsvalue is class-type*, *jsvalue is class-of-type*\
2235966- The unit JS provides many utility functions for JSValue, like *hasString, hasValue, isBoolean, isNumber, isInteger, isObject, isClass, isClassInstance, etc..*
2236967
2237968## Accessing JS object properties with the bracket accessor
2238969
2239970Pas2js 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 *TJSObject(AnObject)\['Name'\]:=Value;*\
2240971Another example is the default property of TJSArray, that allows access via integers *aTJSArray\[3\]:=Value;*\
2241972To define your own bracket accessor define a normal index property and define the getter/setter as *external name '\[\]*'.\
2242973Here is an example for a read only accessor:
2243974
2244-<thead>
2245-
2246-</thead>
2247-<tbody>
2248-
2249-<code>{$modeswitch externalclass}</code><br />
2250-<code>type</code><br />
2251-<code>  TExtA = class external name 'ExtA'</code><br />
2252-<code>  private</code><br />
2253-<code>    function GetItems(Index: integer): String; external name '[]';</code><br />
2254-<code>  public</code><br />
2255-<code>    property Items[Index: integer]: String read GetItems; default;</code><br />
2256-<code>  end;</code><br />
2257-<code>var</code><br />
2258-<code>  Obj: TExtA;</code><br />
2259-<code>  s: String;</code><br />
2260-<code>Begin</code><br />
2261-<code>  ... get Obj from somewhere ...</code><br />
2262-<code>  s:=Obj[2];</code><br />
2263-<code>End.</code></td>
2264-
2265-<code>  var $mod = this;</code><br />
2266-<code>  this.Obj = undefined;</code><br />
2267-<code>  this.s = "";</code><br />
2268-<code>  $mod.$main = function () {</code><br />
2269-<code>    $mod.s = Obj[2];</code><br />
2270-<code>  };</code><br />
2271-<code>});</code></td>
2272-
2273-</tbody>
975+| Pascal | JavaScript |
976+|---|---|
977+| `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.` | `rtl.module("program",["System"],function () {` · ` var $mod = this;` · ` this.Obj = undefined;` · ` this.s = "";` · ` $mod.$main = function () {` · ` $mod.s = Obj[2];` · ` };` · `});` |
2274978
2275979Notes:
2276980
2277981- 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.
2278982
2279983## RTTI - Run Time Type Information
2280984
2281985The 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:
2282986
2283987`    TTypeInfo = class external name 'rtl.tTypeInfo'`\
2284988`    public`\
2285989`      Name: String external name 'name';`\
2286990`      Kind: TTypeKind external name 'kind';`\
2287991`    end;`\
2288992`    TTypeInfoClass = class of TTypeInfo;`\
2289993
2290994`    TTypeInfoInteger = class external name 'rtl.tTypeInfoInteger'(TTypeInfo)`\
2291995`    public`\
2292996`      MinValue: NativeInt external name 'minvalue';`\
2293997`      MaxValue: NativeInt external name 'maxvalue';`\
2294998`      OrdType : TOrdType external name 'ordtype';`\
2295999`    end;`\
22961000
22971001The **typeinfo** function works on type, var, const and property identifiers. By default it returns a *pointer*. If the typinfo unit is used it returns the appropiate *TTypeInfo*. For instance *typeinfo(integer)* returns a *TTypeInfoInteger*.\
22981002*Typeinfo* of a *var* or *const* returns the typeinfo of its type, not of its current runtime value. The exception is a class and class-of instance variable (e.g. *var o: TObject; ... typeinfo(o)*), which returns the typeinfo of the current runtime value. If *o* is *nil* it will give a JS error.\
22991003Local types (i.e. inside a procedure) do not have typeinfo.\
23001004Open array parameters are not yet supported.\
23011005Note that FPC *typeinfo(aClassVar)* returns the compiletime type, so it works on *nil*.\
23021006
23031007## Async/AWait
23041008
23051009Pas2js supports the JS operators async and await to simplify the use of Promise. The await operator corresponds to three intrinsic Pas2js functions:
23061010
23071011- *function await(AsyncFunctionWithResultT()): T;* // implicit promise, the inner () can be omitted
23081012- *function await(aType; p: TJSPromise): aType;* // explicit promise requires the resolved type
23091013- *function await(aType; j: jsvalue): aType;* // explicit promise requires the resolved type
23101014
23111015The await function can only be used inside a procedure with the async modifier.\
23121016Example for the explicit promise:
23131017
2314-<thead>
2315-
2316-</thead>
2317-<tbody>
2318-
2319-<code>uses JS, Web;</code><br />
2320-
2321-<code>function ResolveAfter2Seconds: TJSPromise;</code><br />
2322-<code>begin</code><br />
2323-<code>  Result:=TJSPromise.new(procedure(resolve, reject : TJSPromiseResolver)</code><br />
2324-<code>    begin</code><br />
2325-<code>    window.setTimeout(procedure</code><br />
2326-<code>      begin</code><br />
2327-<code>      resolve('resolved');</code><br />
2328-<code>      end,</code><br />
2329-<code>      2000); // wait 2 seconds</code><br />
2330-<code>    end);</code><br />
2331-<code>end;</code><br />
2332-
2333-<code>procedure AsyncCall; async;</code><br />
2334-<code>var s: string;</code><br />
2335-<code>begin</code><br />
2336-<code>  writeln('calling');</code><br />
2337-<code>  s := await(string,resolveAfter2Seconds()); // does not check if result is really a string</code><br />
2338-<code>  writeln(s); // expected output: 'resolved'</code><br />
2339-<code>end;</code><br />
2340-
2341-<code>begin</code><br />
2342-<code>  AsyncCall;</code><br />
2343-<code>end.</code></td>
2344-
2345-<code>  "use strict";</code><br />
2346-<code>  var $mod = this;</code><br />
2347-<code>  this.ResolveAfter2Seconds = function () {</code><br />
2348-<code>    var Result = null;</code><br />
2349-<code>    Result = new Promise(function (resolve, reject) {</code><br />
2350-<code>      window.setTimeout(function () {</code><br />
2351-<code>        resolve("resolved");</code><br />
2352-<code>      },2000);</code><br />
2353-<code>    });</code><br />
2354-<code>    return Result;</code><br />
2355-<code>  };</code><br />
2356-<code>  this.AsyncCall = async function () {</code><br />
2357-<code>    var s = "";</code><br />
2358-<code>    pas.System.Writeln("calling");</code><br />
2359-<code>    s = await $mod.ResolveAfter2Seconds();</code><br />
2360-<code>    pas.System.Writeln(s);</code><br />
2361-<code>  };</code><br />
2362-<code>  $mod.$main = function () {</code><br />
2363-<code>    $mod.AsyncCall();</code><br />
2364-<code>  };</code><br />
2365-<code>});</code></td>
2366-
2367-</tbody>
1018+| Pascal | JavaScript |
1019+|---|---|
1020+| `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.` | `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();` · ` };` · `});` |
23681021
23691022Notes:
23701023
23711024- The await function does only compile time checks, no runtime checks.
23721025- Inside an async function/procedure you can pass a *TJSPromise* to the *exit()* function. For example:\
23731026 *exit(aPromise);*\
23741027 *exit(inherited);*
23751028
23761029## Compiler directives
23771030
23781031In config files:
23791032
23801033- \#IFDEF macroname
23811034- \#IFNDEF macroname
23821035- \#IF expression - same as \$if, except only defines
23831036- \#ELSEIF
23841037- \#ELSE
23851038- \#ENDIF
23861039- \#ERROR text
23871040
23881041In source files:
23891042
23901043- {\$Define *MacroName*}: defines macro *MacroName* with value '1'.
23911044- {\$Define *MacroName:=value*}: defines macro *MacroName* with custom value.
23921045- {\$Undef *MacroName*}: undefines macro *MacroName*.
23931046- {\$IfDef *MacroName*}: if *MacroName* is not defined, skip to next \$Else or \$EndIf. Can be nested.
23941047- {\$IfNDef *MacroName*}: as \$IfDef, except negated.
23951048- {\$If *boolean expression*}: if *expression* evaluates to true (not '0'), skip to next \$Else or \$EndIf. Can be nested.\
23961049 Supported functions and operators:\
23971050 * macro - replaced by its value, a simple define has value '1'
23981051 - defined(macro) - '1' if defined, '0' otherwise
23991052 - undefined(macro) - as *not defined(macro)*
24001053 - option(letter) - same as *{\$IFOpt letter+}*
24011054 - not - first level of precedence
24021055 - *, /, div, mod, and, shl, shr - second level of precedence
24031056 - +, -, or, xor - third level of precedence
24041057 - =, \<\>, \<, \>, \<=, \>= - fourth level of precedence
24051058 - If the operands can be converted to numbers they are combined as numbers, otherwise as strings. Not supported functions and operators:\
24061059 - defined(Pascal identifier), undefined(Pascal identifier)
24071060 - declared(Pascal identifier)
24081061 - in operator
24091062- {\$IfOpt *Letter+,-*}: if *expression* evaluates to true (not '0'), skip to next \$Else or \$EndIf. Can be nested.
24101063- {\$Else}: If previous \$IfDef, \$If or \$IfOpt was skipped, execute next block, otherwise skip.
24111064- {\$ElseIf *boolean expression*} : As \$Else, except with an extra expression like \$if to test. There can be multiple \$elseif.
24121065- {\$EndIf} : ends an \$IfDef block
24131066- {\$mode delphi} or {\$mode objfpc} : Same as -Mdelphi or -Mobjfpc, 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.
24141067- {\$modeswitch externalclass} : allow declaring external classes
24151068- {\$modeswitch arrayoperators} : allow + operator to concatenate arrays, default in mode delphi
24161069- {\$modeswitch OmitRTTI} : treat published sections as public
24171070- {\$macro on\|off} enables macro replacements. Only macros with a value are replaced. Macros are never replaced inside directives.
24181071- {\$I filename} or {\$include filename} - insert include file
24191072- {\$I %param%} :
24201073 - %date%: current date as string literal, '\[yyyy/mm/dd\]'
24211074 - %time%: current time as string literal, 'hh:mm:ss'. Note that the inclusion of %date% and %time% 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.
24221075 - %file%: current source filename as string literal, e.g. **unit1.pas**
24231076 - %line%: current source line number as string literal, e.g. **123**
24241077 - %linenum%: current source line number as integer, e.g. *123*
24251078 - %currentroutine%: name of current routine as string literal
24261079 - %pas2jstarget%, %pas2jstargetos%, %fpctarget%, %fpctargetos%: target os as string literal, e.g. 'Browser'
24271080 - %pas2jstargetcpu%, %fpctargetcpu%: target cpu as string literal, e.g. 'ECMAScript5'
24281081 - %pas2jsversion%, %fpcversion%: compiler version as strnig literal, e.g. '1.0.2'
24291082 - 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 *''* is inserted.
24301083- {\$Warnings on\|off}
24311084- {\$Notes on\|off}
24321085- {\$Hints on\|off}
24331086- {\$Error text} : emit an error
24341087- {\$Warning text} : emit a warning
24351088- {\$Note text} : emit a note
24361089- {\$Hint text} : emit a hint
24371090- {\$Message hint-text} : emit a hint
24381091- {\$Message hint\|note\|warn\|error\|fatal text} : emit a message
24391092- {\$Warn identifier on\|off\|default\|error} : enable or disable a specific hint.\
24401093 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.\
24411094 Identifier can be a message number as written by -vq or one of the following case insensitive:\
24421095 * CONSTRUCTING_ABSTRACT : Constructing an instance of a class with abstract methods.
24431096 - IMPLICIT_VARIANTS : Implicit use of the variants unit.
24441097 - NO_RETVAL : Function result is not set
24451098 - SYMBOL_DEPRECATED : Deprecated symbol.
24461099 - SYMBOL_EXPERIMENTAL : Experimental symbol
24471100 - SYMBOL_LIBRARY
24481101 - SYMBOL_PLATFORM : Platform-dependent symbol.
24491102 - SYMBOL_UNIMPLEMENTED : Unimplemented symbol.
24501103 - HIDDEN_VIRTUAL : method hides virtual method of ancestor
24511104 - GARBAGE : text after final end.
24521105 - BOUNDS_ERROR : range check errors
24531106 - MESSAGE_DIRECTIVE : user defined \$message
24541107- {\$M+}, {\$TypeInfo on} : switches default visibility for class members from public to published
24551108- {\$ScopedEnums on\|off} disabled(default): propagate enums to global scope, enable: needs fqn e.g. TEnumType.EnumValue.
24561109- {\$C+} generate code for assertions
24571110- {\$H+} , but not {\$H-}
24581111- {\$J-}, {\$WriteableConst off} : Typed const become readonly. For example *const i:byte=3; ... i:=4* creates a compile time error.
24591112- {\$M+} : allow published members
24601113- {\$Q+} : not yet supported, ignored
24611114- {\$R+}, {\$RangeChecks on} : compile time range check hints become errors and add runtime range checks for assignments.
24621115- {\$ObjectChecks on\|off} :
24631116 - Verify method calls, i.e. check at runtime in every method if *Self* is a descendant class.
24641117 - Check type casts, e.g. *TBird(AnObject)* becomes *AnObject as TBird*
24651118- {\$DispatchField Msg} : enable checking *message number* methods for record field name "Msg"
24661119- {\$DispatchStrField MsgStr} : enable checking *message string* methods for record field name "Msg"
24671120- {\$Optimization Name} : same as command line option -OoName
24681121- {\$linklib filename \[alias\]}:
24691122 - filename filename to import.
24701123 - alias 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.
24711124
24721125Defines:
24731126
24741127- PAS2JS
24751128- PAS2JS_FULLVERSION - major*1000+minor*100+release, e.g. 1.2.3 = 10203
24761129- Target platform: Browser, NodeJS, Pas2JSTargetOS=\<value\>
24771130- Target processor: ECMAScript5, ECMAScript6, ECMAScript=5, Pas2JSTargetCPU=\<value\>
24781131- Mode: DELPHI, OBJFPC
24791132
24801133## Numbers
24811134
24821135`JavaScript only supports double. All Pascal number types and enum values are mapped to this. A double supports integers from`\
24831136` MinInteger = -$10000000000000;`\
24841137` MaxInteger = $fffffffffffff;`\
24851138` MinDouble = 5.0e-324;`\
24861139` MaxDouble = 1.7e+308;`\
24871140
24881141` Intrinsic integer types:`
24891142
24901143- Byte - unsigned 8-bit
24911144- ShortInt - signed 8-bit
24921145- Word - unsigned 16-bit
24931146- SmallInt - signed 16-bit
24941147- LongWord - unsigned 32-bit
24951148- LongInt - signed 32-bit
24961149- NativeUInt - unsigned 53-bit
24971150- NativeInt - signed 54-bit
24981151
24991152Notes:
25001153
25011154- Division by zero does not raise an exception. 0/0 results in NaN, positive/0 is Infinity, negative/0 is -Infinity.
25021155- NaN\<\>NaN
25031156- Overflows work differently. For example in Delphi adding 100 to a byte of 200 gives *300 and \$ff = 44*, while in pas2js it gives 300, which is not a byte anymore.
25041157- Math.isNan(double) tests for NaN. Otherwise false. isNan(Infinity)=false.
25051158- Math.isFinite(double) tests if not NaN, positive or negative infinity.
25061159- Math.isInfinite(double) tests if positive or negative infinity.
25071160- For more functions see unit Math.
25081161- 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.
25091162
25101163## Other supported Pascal elements
25111164
25121165- **break**, **continue**, **exit**, **exit()**
25131166- **chr**, **ord**
25141167- alias type and type alias type
25151168- *inc()* and *dec()* to += -=
25161169- Converts "a div b" to "Math.floor(a / b)"
25171170- and, or, xor, not: logical and bitwise
25181171- Name conflicts with JS identifiers are automatically fixed by changing case. For example a Pascal function "*apply"* is renamed to "*Apply*".
25191172- uses unitname in 'filename'. In *\$mode delphi* the in-filenames are only allowed in the program and the unitname must fit the filename, e.g. *uses unit1 in 'sub/Unit1.pas*.\
25201173 In *\$mode objfpc* units can use in-filenames too and alias are allowed, e.g. *uses foo in 'bar.pas*'.
25211174- The intrinsic procedure **str** works with boolean, integer, float and enumvalue.\
25221175 Additionally there is **str** 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).\
25231176 Width and precision is supported. str(i:10) will add spaces to the left to fill up to 10 characters. str(aDouble:1:5) returns a string in decimal format with 5 digits for the fraction.
25241177- Intrinsic procedure WriteStr(out s: string; params...)
25251178- *Debugger;* converts to *debugger;*. If a debugger is running it will break on this line just like a break point.
25261179- *function concat(string1,string2,...): string* since 1.3
25271180- *\$mode delphi: function lo\|hi(integer): byte* since 1.3
25281181- *\$mode objfpc: function lo\|hi(integer): byte\|word\|longword* since 1.3
25291182- *function GetTypeKind(Type or Var): TTypeKind;* since 1.5
25301183
25311184## Not supported elements
25321185
25331186- Class destructor
25341187- Enums with custom values
25351188- Global properties
25361189- Futures
25371190- Inline
25381191- Objects
25391192- Operator overloading
25401193- Pointer arithmetic
25411194- Package
25421195- Resources
25431196- RTTI extended, \$RTTI
25441197- Variant records
25451198- Variants
25461199
25471200## JavaScript Version
25481201
25491202Code generation depending on -P option:
25501203
25511204- ECMAScript5
25521205- ECMAScript6: using 0b for binary literals, and 0o for octal literals
25531206
25541207## Creating source maps
25551208
25561209Source maps are files telling the browser what JavaScript comes from which original source (e.g. Pascal file), similar to debug information in FPC/Delphi.\
25571210In 2017 FireFox and Chrome supports source maps.\
25581211You can enable generating source map files by using the *-Jm* option.\
25591212The compiler generates one module.js.map file for every generated module.js file. The last line of the .js file contains the line\
25601213*//# sourceMappingURL=module.js.map*\
25611214telling the browser where to find the source map.\
25621215The 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 *-Jmbasedir=\<x\>*. For example *-JmC:\www\pas* creates paths relative to C:\www\pas.\
25631216You can set the base URL, where the browser finds the Pascal sources, by passing the *-Jmsourceroot=\<x\>* option. For example *-Jmsourceroot=<http://www.yoursite.com/pas/>*. The browser prepends this to the source map filenames when downloading the original source files (e.g. the .pas files).\
25641217You can include the whole Pascal sources in the source map using the option *-Jminclude*.\
25651218
25661219To show the generated mapping for each line you can use the tool fpc/packages/fcl-js/examples/srcmapdump.\
25671220
25681221- Option -JmXSSIHeader: According to the specifications sourcemap should start with the XSSI (cross site script inclusion) protection header *)\]}*'. If your browser does not support that, disable it with *-JmXSSIHeader-*. See here the specs: <https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit#heading=h.h7yy76c5il9v>
25691222
25701223## See Also
25711224
25721225- [[pas2js]]
25731226
25741227---
25751228*From the Free Pascal wiki, page "Pas2js Transpiler", as it stood on 2023-05-08 after a change by Maxerist, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
25761229Category: Pas2js

Back to history