Giter Club home page Giter Club logo

besen's Introduction

BESEN is an acronym for "B ero's E cma S cript E ngine", and it is a complete ECMAScript Fifth Edition Implemention in Object Pascal, which is compilable with Delphi >=7 and Free Pascal >= 2.5.1 (maybe also 2.4.1).

BESEN is licensed under the LGPL v2.1 with static-linking-exception.

Support me

Support me at Patreon

Features

  • Complete implementation of the ECMAScript Fifth Edition standard
  • Own bytecode-based ECMA262-complaint Regular Expression Engine
  • Incremental praise/exact mark-and-sweep garbage collector
  • Unicode UTF8/UCS2/UTF16/UCS4/UTF32 support (on ECMAScript level, UCS2/UTF16)
  • Compatibility modes, for example also a facile Javascript compatibility mode
  • Bytecode compiler
  • Call-Subroutine-Threaded Register-based virtual machine
  • Context-Threaded 32-bit x86 and 64-bit x64/AMD64 Just-in-Time Compiler (a ARMv7 EABI JIT for ARM CPUs with VFPv3 instruction set is planned)
  • Constant folding
  • Dead code elimination
  • Abstract-Syntax-Tree based optimizations
  • Type inference (both exact and speculative)
  • Polymorphic Inline Cache based on object structure and property key IDs
  • Perfomance optimized hash maps
  • Self balanced trees (for example to sort on-the-fly linked list items of hash maps for very fast enumeration of array objects)
  • Easy native Object Pascal class integration (properties per RTTI and published methods per by-hand-parsing of the native virtual method table)

Hint

  • Function code runs faster than global non-function code, because function-local variable accesses will be always identifier index lookups instead of identifier string lookups.
  • Strict code runs faster than non-strict code, for that reason please use preferably "use strict" where is it possible, because at strict code is the arguments object creation cheaper at funtion calls, for example no setter/getter creation for each function argument in the arguments object.
  • Scoping and some other things between ECMAScript 3rd Edition and ECMAScript 5th Edition are a bit different, so the execution perfomance of ES3 code in a ES5-complaint engine can be strong faster or even strong slower, depends on the individual situation/code.
  • No all old ES3 code must be runnable in a ES5-complaint engine, but the most old ES3 code should be runnable, I think.

Flattr

[Flattr](http://flattr.com/thing/74902/BESEN-ECMAScript-5th-Edition-Engine Flattr)

Donate

Go to my donate page

IRC channel

IRC channel #besen on Freenode

Contact

Drop me a mail at benjamin at rosseaux dot com for bug reports, questions, feature suggestions or whatever. :-)

besen's People

Contributors

bero1985 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

besen's Issues

The application freezes at TBESEN.Free after compile error.

As example:

var
  B: TBESEN;
begin
  B := TBESEN.Create;
  try
    try
      B.Execute('+'); // Compile error
    except on E: Exception do
      // Ignore
    end;
  finally
    B.Free; // Hungs here
  end;
end;  

Setting:

{$define PurePascal}
{$define PurePascalExecuteByteCode}

Lazarus 2.2.6 (rev Unknown) FPC 3.2.2 x86_64-darwin-cocoa

The Asian language string cannot be displayed correctly

Thank you for your amazing project.
When I trying,I find the Asian language string cannot be displayed correctly. The Hex value after the Parsing is $3F $3F.... $3F.....

for example:
prompt("测试");
the "测试" can't display correctly,and the "测试" will replaced with Hex" $3F $3F $3F $3F".

Can you check the procedure NextChar in BESENParser.pas

Env: Win10 + Delphi 10.1

Creating besen objects from application side + passing to functions

type..

TActorInterface = class(TBESENNativeObject)

class is registered properly so it can be prototyped from:

BesenInst.RegisterNativeObject('Actor', TActorInterface);

So i try to create a object on my side, and pass it as parameter to javascript

    JsPlayer: TBESENValue;

	AResult: TBESENValue;
    ta: Tactor;
    JsCreatedPlayer: TActorInterface;

begin

 				TBESEN(BesenInst).GarbageCollector.Protect(OnCreatePlayer);

 			    try
 			       AResult.ValueType := bvtBOOLEAN;

                   ta:= Tactor.GetFromIndex(PlayerID);

                   JsCreatedPlayer:= TActorInterface.Create(BesenInst, TBESEN(BesenInst).ObjectPrototype, false);
                   JsCreatedPlayer.SetHandle(ta.GetHandle());

 				   TBESEN(BesenInst).GarbageCollector.Add(JsCreatedPlayer);
                   TBESEN(BesenInst).GarbageCollector.Protect(TBESENObject(JsCreatedPlayer));

                   a[0]:= @JsPlayer;
                   JsPlayer := BESENObjectValue(TBESENObject(JsCreatedPlayer));
                   // todo: add parameter player ID

 			       OnCreatePlayer.Call(BESENObjectValue(OnCreatePlayer), @a, 2, AResult);

 			    except
 			       on e: EBESENError do
 			       begin
 			         addtochat(Format('%s ( Line %d ): %s', [e.Name, TBESEN(BesenInst).LineNumber, e.Message]));
 			       end;

 			       on e: exception do
 			       begin
 			         addtochat(Format('%s ( Line %d ): %s', ['Exception', TBESEN(Instance).LineNumber, e.Message]));
 			       end;
 			    end;


If i print the object it's:
[object TActorInterface$Constructor] {}

Looks like some sort of empty object, it doesn't function properly in javascript (cannot change properties, etc.. ).

I've based my code on what i saw in https://github.com/Coldzer0/Cmulator/ project, i'm guessing i did something very wrong.

I'd just like to create an instance of native object, and pass it to function, so that properties and all can be correctly used as if it was created within javascript.

If you have a better method of contacting i'll take it, as i'm abusing tickets for help / support :( i'm in #besen channel but you are usually not reachable there.

This sprintf script outputs NaN in this script

This function is an sprintf function from https://github.com/alexei/sprintf.js/blob/master/src/sprintf.js.
Numbers produce a NaN error. I have tested it with Mozilla's Javascript and it works

(function(window) {
    var re = {
        not_string: /[^s]/,
        number: /[dief]/,
        text: /^[^\x25]+/,
        modulo: /^\x25{2}/,
        placeholder: /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fiosuxX])/,
        key: /^([a-z_][a-z_\d]*)/i,
        key_access: /^\.([a-z_][a-z_\d]*)/i,
        index_access: /^\[(\d+)\]/,
        sign: /^[\+\-]/
    }

    function sprintf() {
        var key = arguments[0], cache = sprintf.cache
        if (!(cache[key] && cache.hasOwnProperty(key))) {
            cache[key] = sprintf.parse(key)
        }
        return sprintf.format.call(null, cache[key], arguments)
    }

    sprintf.format = function(parse_tree, argv) {
        var cursor = 1, tree_length = parse_tree.length, node_type = "", arg, output = [], i, k, match, pad, pad_character, pad_length, is_positive = true, sign = ""
        for (i = 0; i < tree_length; i++) {
            node_type = get_type(parse_tree[i])
            if (node_type === "string") {
                output[output.length] = parse_tree[i]
            }
            else if (node_type === "array") {
                match = parse_tree[i] // convenience purposes only
                if (match[2]) { // keyword argument
                    arg = argv[cursor]
                    for (k = 0; k < match[2].length; k++) {
                        if (!arg.hasOwnProperty(match[2][k])) {
                            throw new Error(sprintf("[sprintf] property '%s' does not exist", match[2][k]))
                        }
                        arg = arg[match[2][k]]
                    }
                }
                else if (match[1]) { // positional argument (explicit)
                    arg = argv[match[1]]
                }
                else { // positional argument (implicit)
                    arg = argv[cursor++]
                }

                if (get_type(arg) == "function") {
                    arg = arg()
                }

                if (re.not_string.test(match[8]) && (get_type(arg) != "number" && isNaN(arg))) {
                    throw new TypeError(sprintf("[sprintf] expecting number but found %s", get_type(arg)))
                }

                if (re.number.test(match[8])) {
                    is_positive = arg >= 0
                }

                switch (match[8]) {
                    case "b":
                        arg = arg.toString(2)
                    break
                    case "c":
                        arg = String.fromCharCode(arg)
                    break
                    case "d":
                    case "i":
                        arg = parseInt(arg, 10)
                    break
                    case "e":
                        arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential()
                    break
                    case "f":
                        arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg)
                    break
                    case "o":
                        arg = arg.toString(8)
                    break
                    case "s":
                        arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg)
                    break
                    case "u":
                        arg = arg >>> 0
                    break
                    case "x":
                        arg = arg.toString(16)
                    break
                    case "X":
                        arg = arg.toString(16).toUpperCase()
                    break
                }
                if (re.number.test(match[8]) && (!is_positive || match[3])) {
                    sign = is_positive ? "+" : "-"
                    arg = arg.toString().replace(re.sign, "")
                }
                else {
                    sign = ""
                }
                pad_character = match[4] ? match[4] === "0" ? "0" : match[4].charAt(1) : " "
                pad_length = match[6] - (sign + arg).length
                pad = match[6] ? (pad_length > 0 ? str_repeat(pad_character, pad_length) : "") : ""
                output[output.length] = match[5] ? sign + arg + pad : (pad_character === "0" ? sign + pad + arg : pad + sign + arg)
            }
        }
        return output.join("")
    }

    sprintf.cache = {}

    sprintf.parse = function(fmt) {
        var _fmt = fmt, match = [], parse_tree = [], arg_names = 0
        while (_fmt) {
            if ((match = re.text.exec(_fmt)) !== null) {
                parse_tree[parse_tree.length] = match[0]
            }
            else if ((match = re.modulo.exec(_fmt)) !== null) {
                parse_tree[parse_tree.length] = "%"
            }
            else if ((match = re.placeholder.exec(_fmt)) !== null) {
                if (match[2]) {
                    arg_names |= 1
                    var field_list = [], replacement_field = match[2], field_match = []
                    if ((field_match = re.key.exec(replacement_field)) !== null) {
                        field_list[field_list.length] = field_match[1]
                        while ((replacement_field = replacement_field.substring(field_match[0].length)) !== "") {
                            if ((field_match = re.key_access.exec(replacement_field)) !== null) {
                                field_list[field_list.length] = field_match[1]
                            }
                            else if ((field_match = re.index_access.exec(replacement_field)) !== null) {
                                field_list[field_list.length] = field_match[1]
                            }
                            else {
                                throw new SyntaxError("[sprintf] failed to parse named argument key")
                            }
                        }
                    }
                    else {
                        throw new SyntaxError("[sprintf] failed to parse named argument key")
                    }
                    match[2] = field_list
                }
                else {
                    arg_names |= 2
                }
                if (arg_names === 3) {
                    throw new Error("[sprintf] mixing positional and named placeholders is not (yet) supported")
                }
                parse_tree[parse_tree.length] = match
            }
            else {
                throw new SyntaxError("[sprintf] unexpected placeholder")
            }
            _fmt = _fmt.substring(match[0].length)
        }
        return parse_tree
    }

    var vsprintf = function(fmt, argv, _argv) {
        _argv = (argv || []).slice(0)
        _argv.splice(0, 0, fmt)
        return sprintf.apply(null, _argv)
    }

    /**
     * helpers
     */
    function get_type(variable) {
        return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase()
    }

    function str_repeat(input, multiplier) {
        return Array(multiplier + 1).join(input)
    }

    /**
     * export to either browser or node.js
     */
    if (typeof exports !== "undefined") {
        exports.sprintf = sprintf
        exports.vsprintf = vsprintf
    }
    else {
        window.sprintf = sprintf
        window.vsprintf = vsprintf

        if (typeof define === "function" && define.amd) {
            define(function() {
                return {
                    sprintf: sprintf,
                    vsprintf: vsprintf
                }
            })
        }
    }
})(typeof window === "undefined" ? this : window);
animal = cat
amount = 10
sprintf('I have %d %s(s)', amount, animal)

I have NaN cat(s)

object properties: boolean is not supported

If a RegisterNativeObject object property returns boolean, besen is unable to use it:

private function getislocal(): boolean; published property IsLocal: boolean read getislocal;

An integer property however works well and getislocal is called:

private function getislocal(): integer; published property IsLocal: integer read getislocal;

set int64 gives a wrong value

Hello BeRo
while i'm testing setting large values like
18374966859414961920

i test with

var x = 18374966859414961920
undefined
x
18374966859414962000

i try to follow the code and i think the problem is here

DoFastShortest() in BESENNumberUtils

i try to fix but i can't

can you please check it if you have time

thanks

Correct returning of objects

Whenever an instance of class that is registered in besen is created, i put it on a class pointer list internally.

I need a class function on another class - that would return an array of all those instances.

So, gameinterface - return list of all actors:

I have experimented and found a way to return array of strings, this works for strings:

`
procedure TGameInterface.ActorList(const ThisArgument: TBESENValue; Arguments: PPBESENValues; CountArguments: integer; var ResultValue: TBESENValue);
var
i: integer;
ara: TBESENObjectArray;
begin

ResultValue.ValueType:= bvtBOOLEAN;
ResultValue.Bool:= false;

ara:= TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false);

for i:= 0 to BesenActorList.highest do begin

// this works well - returns an string array
ara.Push( BESENStringValue('Test String, ignore.') );
// this will crash besen
    ara.Push( besenobjectvalue(BesenActorList.Data[i]) );

end;

resultvalue:= BESENObjectValue(ara);

end;
`

If i return those objects, what happens is i get garbage collector crash in TBESENGarbageCollectorObjectList.Remove:

[Window Title]
Error

[Content]
Project tdc raised exception class 'External: SIGSEGV'.

In file 'besen\src\BESENGarbageCollector.pas' at line 518:
AObject.GarbageCollectorObjectListPrevious.GarbageCollectorObjectListNext:=AObject.GarbageCollectorObjectListNext;

[OK]

while i cannot find any example of this.. i'm not sure what the problem is with garbage collector, the crash happens when trying to access any property of the array or loop the array via for i in array in script.

The resulting array can be sent to stuff like internal print() function and that works! no crash there.

Call stack of crash:

`
#0 REMOVE(0xfeeefeee, 0x26e4f404) at besen\src\BESENGarbageCollector.pas:518
#1 GRAYIT(0xfeeefeee, 0x26e4f404) at besen\src\BESENGarbageCollector.pas:642
#2 GRAYVALUE(0xfeeefeee, {STR = 0xfeeefeee <error: Cannot access memory at address 0xfeeefeee>, REFERENCEBASE = {STR = 0xfeeefeee <error: Cannot access memory at address 0xfeeefeee>, VALUETYPE = 4277075694, BOOL = 4277075694, NUM = -2.6569842580370804e+303, OBJ = 0xfeeefeee, ENVREC = 0xfeeefeee}, VALUETYPE = 4277075694, BOOL = 4277075694, NUM = -2.6569842580370804e+303, OBJ = 0xfeeefeee, REFERENCEISSTRICT = 4277075694, REFERENCEHASH = 4277075694, REFERENCEINDEX = -17891602, REFERENCEID = -17891602, LOCALINDEX = -17891602, ENVREC = 0xfeeefeee}) at besen\src\BESENGarbageCollector.pas:675
#3 MARK(0xfeeefeee) at besen\src\BESENObject.pas:2491
#4 MARK(0xfeeefeee) at besen\src\BESENObjectArray.pas:348
#5 MARK(0xfeeefeee, 0x26e4f404) at besen\src\BESENGarbageCollector.pas:703
#6 COLLECT(0x26e4f404) at besen\src\BESENGarbageCollector.pas:830
#7 TRIGGERCOLLECT(0xfeeefeee) at besen\src\BESENGarbageCollector.pas:727
#8 CALLEX(0x26d3876c, {STR = 0x0, REFERENCEBASE = {STR = 0x0, VALUETYPE = 0, BOOL = false, NUM = 0, OBJ = 0x0, ENVREC = 0x0}, VALUETYPE = 5, BOOL = 651396124, NUM = 3.2183244670254472e-315, OBJ = 0x26d3841c, REFERENCEISSTRICT = 651396124, REFERENCEHASH = 0, REFERENCEINDEX = 0, REFERENCEID = 0, LOCALINDEX = 651396124, ENVREC = 0x26d3841c}, 0x26c91da4, 1, {STR = 0x0, REFERENCEBASE = {STR = 0x0, VALUETYPE = 4, BOOL = 651628940, NUM = 3.2194747308994689e-315, OBJ = 0x26d7118c, ENVREC = 0x26d7118c}, VALUETYPE = 0, BOOL = false, NUM = -2.0222366862929471e+234, OBJ = 0x0, REFERENCEISSTRICT = false, REFERENCEHASH = 4036254262, REFERENCEINDEX = 3, REFERENCEID = 203, LOCALINDEX = 0, ENVREC = 0x0}, false) at besen\src\BESENObjectDeclaredFunction.pas:175
#9 CALL(0xfeeefeee, {STR = 0xfeeefeee <error: Cannot access memory at address 0xfeeefeee>, REFERENCEBASE = {STR = 0xfeeefeee <error: Cannot access memory at address 0xfeeefeee>, VALUETYPE = 4277075694, BOOL = 4277075694, NUM = -2.6569842580370804e+303, OBJ = 0xfeeefeee, ENVREC = 0xfeeefeee}, VALUETYPE = 4277075694, BOOL = 4277075694, NUM = -2.6569842580370804e+303, OBJ = 0xfeeefeee, REFERENCEISSTRICT = 4277075694, REFERENCEHASH = 4277075694, REFERENCEINDEX = -17891602, REFERENCEID = -17891602, LOCALINDEX = -17891602, ENVREC = 0xfeeefeee}, 0xfeeefeee, -17891602, {STR = 0xfeeefeee <error: Cannot access memory at address 0xfeeefeee>, REFERENCEBASE = {STR = 0xfeeefeee <error: Cannot access memory at address 0xfeeefeee>, VALUETYPE = 4277075694, BOOL = 4277075694, NUM = -2.6569842580370804e+303, OBJ = 0xfeeefeee, ENVREC = 0xfeeefeee}, VALUETYPE = 4277075694, BOOL = 4277075694, NUM = -2.6569842580370804e+303, OBJ = 0xfeeefeee, REFERENCEISSTRICT = 4277075694, REFERENCEHASH = 4277075694, REFERENCEINDEX = -17891602, REFERENCEID = -17891602, LOCALINDEX = -17891602, ENVREC = 0xfeeefeee}) at besen\src\BESENObjectDeclaredFunction.pas:132
#10 OBJECTCALLCONSTRUCT(0x2690ce94, 0x26d3876c, {STR = 0x0, REFERENCEBASE = {STR = 0x0, VALUETYPE = 0, BOOL = false, NUM = 0, OBJ = 0x0, ENVREC = 0x0}, VALUETYPE = 5, BOOL = 651396124, NUM = 3.2183244670254472e-315, OBJ = 0x26d3841c, REFERENCEISSTRICT = 651396124, REFERENCEHASH = 0, REFERENCEINDEX = 0, REFERENCEID = 0, LOCALINDEX = 651396124, ENVREC = 0x26d3841c}, 0x26c91da4, 1, false, {STR = 0x0, REFERENCEBASE = {STR = 0x0, VALUETYPE = 4, BOOL = 651628940, NUM = 3.2194747308994689e-315, OBJ = 0x26d7118c, ENVREC = 0x26d7118c}, VALUETYPE = 0, BOOL = false, NUM = -2.0222366862929471e+234, OBJ = 0x0, REFERENCEISSTRICT = false, REFERENCEHASH = 4036254262, REFERENCEINDEX = 3, REFERENCEID = 203, LOCALINDEX = 0, ENVREC = 0x0}) at besen\src\BESEN.pas:773
#11 OBJECTCALL(0xfeeefeee, 0xfeeefeee, <error reading variable: Cannot access memory at address 0xfeeefeee>, 0xfeeefeee, 652538884, <error reading variable: Cannot access memory at address 0xfeeefeee>) at besen\src\BESEN.pas:787
#12 OPTRACECALL(0x26e7df5c, 0x26dce2fc) at besen\src\BESENCodeContext.pas:3040
#13 ?? at :0

`

Not build In Delphi 10 Seattle

Please add in BESEN.inc
{$ifdef ver290}
{$define DelphiXE8}
{$define DelphiXE7}
{$define DelphiXEAndUp}
{$define DelphiXE2AndUp}
{$define DelphiXE3AndUp}
{$define DelphiXE4AndUp}
{$define DelphiXE5AndUp}
{$define DelphiXE6AndUp}
{$define DelphiXE7AndUp}
{$define DelphiXE8AndUp}
{$define Delphi2009AndUp}
{$endif}
{$ifdef ver300}
{$define DelphiXE9}
{$define DelphiXE8}
{$define DelphiXE7}
{$define DelphiXEAndUp}
{$define DelphiXE2AndUp}
{$define DelphiXE3AndUp}
{$define DelphiXE4AndUp}
{$define DelphiXE5AndUp}
{$define DelphiXE6AndUp}
{$define DelphiXE7AndUp}
{$define DelphiXE8AndUp}
{$define DelphiXE9AndUp}
{$define Delphi2009AndUp}
{$endif}

NativeObject string properties

Hi Benjamin!
BESEN does not see native object's string properties.
Or maybe I did something wrong?

program BESENTest;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  BESEN,
  BESENValue,
  BESENObject,
  BESENConstants,
  BESENNativeObject;

type
  TScriptSys = class
  public
    procedure print(const ThisArgument: TBESENValue; Arguments: PPBESENValues; CountArguments: integer; var AResult:TBESENValue);
  end;

  TTestClass = class(TBESENNativeObject)
  private
    fTestKey: String;
  protected
    procedure ConstructObject(const ThisArgument: TBESENValue; Arguments: PPBESENValues; CountArguments: integer); Override;
  public
    constructor Create(AInstance: TObject; APrototype: TBESENObject=nil; AHasPrototypeProperty: longbool=false); Overload; Override;
  published
    property testKey: String read fTestKey;
  end;

var
  BesenInst: TBesen;
  ScriptSys: TScriptSys;

procedure TScriptSys.print(const ThisArgument: TBESENValue; Arguments: PPBESENValues; CountArguments: Integer; var AResult: TBESENValue);
begin
  writeLn(TBESEN(BesenInst).ToStr(Arguments^[0]^));
end;

constructor TTestClass.Create(AInstance: TObject; APrototype: TBESENObject=nil; AHasPrototypeProperty: longbool=false);
begin
  inherited Create(AInstance, APrototype, AHasPrototypeProperty);
  fTestKey := 'test string value';
end;

procedure TTestClass.ConstructObject(const ThisArgument: TBESENValue; Arguments: PPBESENValues; CountArguments: integer);
begin
  inherited ConstructObject(ThisArgument, Arguments, CountArguments);
end;

begin
  BesenInst := TBesen.Create(COMPAT_JS);
  ScriptSys := TScriptSys.Create;
  BesenInst.ObjectGlobal.RegisterNativeFunction('print', ScriptSys.Print, 1, []);
  BesenInst.RegisterNativeObject('Test', TTestClass);
  BesenInst.Execute(
    'var obj = new Test();' +
    'print(obj.testKey);' +
    'print(JSON.stringify(obj));'
  );
  readLn;
end.

Calling object prototype functions does not work.

I'm really determined to use besen in my project, and am still working on my game with it and writing a tutorial for others to do so, but i have a odd issue which i cannot figure out how to do properly, but it's most likely a bug:

I have registered native object:

BesenInst.RegisterNativeObject('Actor', TActorInterface);
The object has a property for OnCreate:

property OnCreate : TBESENObjectFunction read FOnCreate write FOnCreate;
In Javascript i've created an additional function on class:

Actor.prototype.OnCreate = function(OtherPlayer, AIClass) {
	
	console.log('actor_stack pushing - Actor.OnCreate')
	actor_stack.push(self);
	
}

Inside the constructor, i am attempting to call this function:

procedure TActorInterface.ConstructObject(const ThisArgument: TBESENValue; Arguments: PPBESENValues; CountArguments: integer);

...

	if Assigned(FOnCreate) then begin

		TBESEN(BesenInst).GarbageCollector.Protect(OnCreate);

	    try

	        AResult.ValueType := bvtBOOLEAN;
		    OnCreate.Call(BESENObjectValue(OnCreate), @CallParams, 3, AResult);

	    except

	       on e: exception do HandleBesenException(e);

	    end;

		TBESEN(BesenInst).GarbageCollector.Unprotect(OnCreate);

	end; 

This however does not work as planned, it does seem to work if a function is added on an instance of class itself - but how do i call a prototype method added in javascript - Assigned(FOnCreate) check fails and nothing is called.

Omiting assigned check does not work either.

I've also tried to check prototype - Prototype.HasProperty('OnCreate') to no avail.

I'm not totally sure how i should be handling this, any help will be appreciated.

var a=0; reports undefined error

Thanks for your great job

there is an issue, in shell I input

   var a=0; 

it reports undefined error

I have to remove 'var', then it works

Is it not standard javascript?

Thanks

Z Wang

Spelling mistake in repo description... "implemention" should say "implementation"

"Complete ECMAScript Fifth Edition Implemention in Object Pascal"

should be:

"Complete ECMAScript Fifth Edition Implementation in Object Pascal"

"and it is a complete ECMAScript Fifth Edition Implemention"

should be:

"and it is a complete ECMAScript Fifth Edition Implementation"

Also:

"Perfomance optimized hash maps"

should say:

"Performance optimized hash maps"

and:

"the execution perfomance of ES3 code in a ES5-complaint engine"

should say:

"the execution performance of ES3 code in an ES5-complaint engine"

Can you help me.

Dear Sir.
I am very interested in your project now.
By the way, I am a beginner so I don't know how to run this GitHub project and how to check the result
I don't know anything.
I was tried to run myself but it I can't.
Can you help.
I will wait for your favorable reply.
Thank you very much!

just a heads up about the other problem..

Regarding #17 since ticket is closed, i assume you didn't get notification about the final solution and cause of the problem:

I did some homework and determined that this is caused by verify method calls -CR option being on (not to be confused with -Cr / range checks)

-CR
Generate checks when calling methods to verify if the virtual method table for that object is valid.

If this is used, RegisterNativeObject fails as described, probably will also fail in fpc 3.1.1.

Are you thinking about supporting ES2015 either in addition to or instead of ES5?

I was very impressed by BESEN when it first came out. A complete implementation of ES5 just weeks after the spec was published, and a year before Mozilla, Google, Apple, Microsoft, Opera, and all the others.

Well, now ES2015 has been released and ES2016 is already in the works, and it's the same situation: I'd like to play around with it, but there is no compliant implementation yet. Specifically, support for Proper Tail Calls is severely lacking across the board. (To be fair, depending on the exact design of the engine, that one might be the hardest one to retrofit … or it might fall out quite naturally.)

Are you intending to support ES2015 (and beyond) either in addition to or instead of ES5 or is BESEN strictly an ES5 engine?

Problem with file IO

I have a problem with file operations, specifically when there is an exception while writing to a file (when the file does not exist in this instance). When I call Reset(F); on a non existing file, the program just crashes with no message. This only happens after I execute some JavaScript code.

I noticed that in BESENShell, you are calling the Reset function like this {$i-}reset(f,1);{$i+};. Why is it necessary to supress thrown exceptions like this? Are there any other situations, where I can run into this error?

Here is some code that results in a crash. Thanks for your help.

program BESENTest;

{$APPTYPE CONSOLE}

uses
  SysUtils, BESEN, BESENValue, BESENTypes, BESENASTNodes, BESENNativeObject, BESENNumberUtils;

var
  lResult : TBESENValue;
  lResultStr: String;
  lBesen : TBESEN;
  F: file of char;

  function BesenValToStr(aBesenVal : TBESENValue):string;
  begin

    case aBesenVal.ValueType of
      bvtUNDEFINED:     Result := '';
      bvtNULL:          Result := '<null>';
      bvtBOOLEAN:       Result := BoolToStr(aBesenVal.Bool);
      bvtNUMBER:        Result := FloatToStr(aBesenVal.Num);
      bvtSTRING:        Result := aBesenVal.Str;
      bvtOBJECT:        Result := '<object>';
      bvtREFERENCE:     Result := '<reference>';
      bvtLOCAL:         Result := '<local>';
      bvtNONE:          Result := '<none>';
    end;
  end;

begin
  try
    lBesen := TBESEN.Create();
    try
      lResult := lBesen.Execute('1+1');
      lResultStr := BesenValToStr(lResult);
      Writeln(lResultStr);
    finally
      lBesen.Free;
    end;

    AssignFile(F,'doesnotexist.log');
    try
      try
        Reset(F);
        //{$i-}Reset(f);{$i+};
      finally
        CloseFile(F);
      end;
    except
      on Ex: Exception do
        Writeln(Ex.Classname, ': ', Ex.Message);
    end;

    ReadLn;

  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;
end.

TBESEN.RegisterNativeObject - fault with freepascal

No issues with RegisterNativeObject in delphi, however in freepascal 3.0.4, this function fails with error 219 (Invalid typecast) at line TBESENObject(v.Obj):=AClass.Create(self,ObjectPrototype);

Looks like RTL problem?

Make compile for XE8 & MacOS

Hello,

currently besen does not compile for XE8 & MacOS target.
Needed changes:

Besen.inc:
{$ifdef ver290} // XE8
{$define DelphiXE7}
{$define DelphiXEAndUp}
{$define DelphiXE2AndUp}
{$define DelphiXE3AndUp}
{$define DelphiXE4AndUp}
{$define DelphiXE5AndUp}
{$define DelphiXE6AndUp}
{$define DelphiXE7AndUp}
{$define Delphi2009AndUp}
{$endif}
{$ifdef ver300} // upcoming XE9
{$define DelphiXE7}
{$define DelphiXEAndUp}
{$define DelphiXE2AndUp}
{$define DelphiXE3AndUp}
{$define DelphiXE4AndUp}
{$define DelphiXE5AndUp}
{$define DelphiXE6AndUp}
{$define DelphiXE7AndUp}
{$define Delphi2009AndUp}
{$endif}

BesenLocale.pas for MacOS:

for i:= 1 to 12 do begin
BESENLocaleFormatSettings.ShortMonthNames[i]:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.ShortMonthNames[i]{$else}SysUtils.ShortMonthNames[i]{$endif};
BESENLocaleFormatSettings.LongMonthNames[i]:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.LongMonthNames[i]{$else}SysUtils.LongMonthNames[i]{$endif};
end;
for i:=1 to 7 do begin
BESENLocaleFormatSettings.ShortDayNames[i]:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.ShortDayNames[i]{$else}SysUtils.ShortDayNames[i]{$endif};
BESENLocaleFormatSettings.LongDayNames[i]:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.LongDayNames[i]{$else}SysUtils.LongDayNames[i]{$endif};
end;

jQuery very long time generate byte code.

Hi BeRo! BESEN is very good!
Sorry my bad english.
I trying make non visual browser with BESEN for executing javascript.
But when i try executing jQuery v1.8.3 procdedure BESENCompiller.GenerateByteCode very long time.
link for this jQuery https://yastatic.net/jquery/1.8.3/jquery.min.js
To check, you can copy the jQuery code in an BESEN IDE and press "F9". On my computer 35sec befor error message.

Also there are some errors when compiling the example in module BESENDecompliler in line
bntUNARYVOIDEXPRESSION:
begin
Add('void'); /// need "space" after "void" --> 'void '
Visit(TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression);
end;

To check, another error decompiler you may compare JQuery code befor compile and after decompile, BESEN It can not compile a precompiled code.

This js will cause serious slowness in besen

Hi!

I'm very impressed with your code. For the most part I haven't had problems but the js script below seems to cause serious slowness in besen.

function main(a)
{
    if (
        (a == 1) || (a == 1) ||
        (a == 1) || (a == 1) ||
        (a == 1) || (a == 1) ||
        (a == 1) || (a == 1) ||
        (a == 1) || (a == 1) ||
        (a == 1) || (a == 1) ||
        (a == 1) || (a == 1) ||
        (a == 1) || (a == 1) ||
        (a == 1) || (a == 1) ||
        (a == 1) || (a == 1) ||
        (a == 1) || (a == 1) ||
        (a == 1) || (a == 1)
    ) {
        return -1;
    } else {
        return 1;
    }   
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.