AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Projekte ScriptEngine II (v. 0.6.1)
Thema durchsuchen
Ansicht
Themen-Optionen

ScriptEngine II (v. 0.6.1)

Ein Thema von littleDave · begonnen am 21. Sep 2009 · letzter Beitrag vom 4. Aug 2011
Antwort Antwort
Seite 11 von 12   « Erste     91011 12      
Benutzerbild von littleDave
littleDave
Registriert seit: 27. Apr 2006
Hallo liebe DP'ler

ScriptEngineII


ist der Nachfolger meiner letzten ScriptEngine. Da es sich um ein komplettes Remake handelt, sind die beiden jedoch nicht mehr vergleichbar.

Kurzübersicht
  • Die Script-Engine bnutzt Object-Pascal als Script-Sprache und unterstützt objekt-orientierte Programmierung.
  • Der Quelltext wird in ByteCode übersetzt, der dann von einer optimierten RunTime ausgeführt wird
  • Trotz der Möglichkeiten ist das Interface der Komponente sehr klein und übersichtlich gehalten
  • Für den Einstieg habe ich eine kleine Doku in Form eines PDFs mit in den Download gepackt

Installation
In der ZIP-Datei befindet sich ein Unterordner "src". Diesen extrahiert ihr einfach in einen Ordner eurer Wahl und fügt diesen Ordner dann in den Bibliothekspfad von Delphi hinzu. Im Quelltextorder befindet sich die Datei "ScriptEngine.inc". Diese Datei kann zum konfigurieren der ScriptEngine benutzt werden. Die einzelnen Defines sind (hoffentlich) ausreichend erklärt.

Benötigte Delphi-Version
Bisher hab ich es nur mit Delphi 7 und mit Lazarus getestet. Unter FreePascal hab ich nur ein paar Tests ausgeführt und diese sind auch korrekt gelaufen. Unter Delphi 2009/2010 hab ich die ScriptEngine ebenfalls erfolgreich getestet.

Besonderheiten
  • wenn man innerhalb einer Klassenmethode auf andere Klassenmethoden oder -Variablen zugreifen will, muss man immer "Self" mit angeben
    Update 10.10.2010
    Mit der Version ist 0.5.4.1 ist das nun nicht mehr notwendig!
  • Records sind Referenz-Typen

Bisherige Probleme
Im Moment sind noch folgende Probleme vorhanden:
  • überladene Methoden haben bisher folgende Einschränkung:
    • sie müssen alle vom selben Typ sein (statisch, nicht statisch)
  • der Befehl reintroduce ist noch nicht vorhanden

Lizenz
MPL v1.1 , GPL v3.0 oder LGPL v3.0

Feature-Liste
  • Übersicht
    • Object-Pascal als Dialekt
    • Ganzzahltypen: byte, shortint, word, smallint, cardinal, integer, int64
    • Fließkommatypen: single, double
    • Stringtypen: string, UTF8String, WideString
    • Operatoren: + - * / div mod shr shl and or xor not @
    • Vergleich: = < > <= >= <> is
    • Schleifen: for while repeat for-in-do
    • Datenvergleich: if case
    • Spezielle Blocks: try-finally / try-except
    • Konstanten
    • verschachtelte Unit-Namen (z.B. Unit1.SubUnit.SubUnit)
    • Partielle Units
    • Ablaufkontrolle: continue break exit
    • Exception-Handling und Exception-Throw möglich
    • Multi-Threading-Scripts
  • Methoden
    • Methodentypen: procedure function constructor destructor
    • Methodenparametertypen: const var
    • Methodenoperatoren: virtual abstract override overload forward
    • Import von DLL-Methoden direkt im Script (z.B.: procedure Sleep(milliSec: DWORD); external 'kernel32.dllname 'Sleep'; stdcall; )
    • OOP-Features: inherited
    • Spezielle Operatoren: external export
    • Unterstützte Aufrufkonventionen: register pascal stdcall cdecl
    • Methoden-Pointer
    • Events
  • Records
    • Abschnitte: private protected public
    • Record-Constanten (const-Deklaration in der record-Deklaration)
    • (statische) Record-Methoden
    • (statische) Record-Variablen
    • (statische) Record-Properties
    • Property-Typen: read+write, read-only, write-only
    • Property-Zugriff: direkt, über Methoden, über Methoden mit Parametern
  • Klassen
    • Objekt-Orientierte Programmierung
    • Klassenvererbung
    • Methoden überschreiben
    • Klassen-Sektionen: private protected public
    • Class-Constanten (const-Deklaration in der Class-Deklaration)
    • (statische) Klassenmethoden
    • (statische) Klassenvariablen
    • (statische) Klassenproperties
    • Property-Typen: read+write, read-only, write-only
    • Property-Zugriff: direkt, über Methoden, über Methoden mit Parametern
    • Partielle Klassen (so ähnlich wie bei .NET)
  • Class Helpers
    • Es können zu jedem Datentyp beliebig viele "Helfer-Klassen" erstellt werden
    • gleicher Aufbau wie bei normalen Klassen, nur die Deklaration ist etwas anders:
      • TStringHelper = helper for string
    • Class Helpers erweitern eine Klasse/einen Datentyp ohne die Vererbung zu nutzen
  • Compiler
    • schneller Compiler
    • eingebauter Unit-Cache für schnelleres kompilieren (so wie Delphi-DCUs)
    • partielle Units – mehrere einzelne Units mit gleichem Namen werden zu einer Unit zusammengefasst
    • Linker zum zusammenstellen und zum optimieren des Byte-Codes
    • IntelliSense / Code-Completion und Parameter-Hints-Unterstützung
    • eingebaut als abstrakte Klasse – für SynEdit bereits vorhanden
    • Speichern des kompilierten ByteCodes in einen Stream
  • RunTime
    • schneller ByteCode-Interpreter
    • direkter Aufruf von Delphi-Funktionen
    • Script-Methoden aus dem Programm heraus aufrufbar
    • Script-Methoden als TMethod-Event nativ aufrufbar
    • einfacher Garbage Collector für Script-Klassen (nur falls das Objekt nicht manuell zerstört wurde)
    • eigener Memory-Manager mit Caching für schnelleres Ausführen und für weniger Speicherfragmentierung
    • Exception-Handling
    • Stack-Tracing
  • Quelltext
    • durchgehende Namenskonvention (Units starten mit uSE2 und Klassen mit TSE2)
    • bisher keine Memory-Leaks gefunden

Noch ein paar kurze Hinweise
- Diesmal habe ich leider nicht so viele Beispiele mit in den Download hinein gepackt - es werden aber noch ein paar nachgeliefert

SVN
Ich hab für die Script-Engine ein Source-Forge-Projekt erstellt. Dort sind alle Änderungen auch per SVN abrufbar. Wichtige Releases werd ich natürlich weiterhin hier hochladen

Mitgelieferte IDE
Ich habe die kompilierte Version meiner aktuellen IDE mit in das Download-Paket gepackt. Zusätzlich hab ich den Source in den Unterordner IDEsrc gepackt - zusammen mit den drei kompilierten Packages. Mit der IDE kann man ein paar Testprojekte öffnen, die sich im Unterordner "Projects" befinden.

Ich hoffe, euch gefällt die neue Script-Engine und vielleicht kann der eine oder andere sie ja benutzen.

Download
Auf SourceForge.net (ca. 2,6 MB)

Grüße
Miniaturansicht angehängter Grafiken
screenshot1.png  
Jabber: littleDave@jabber.org
in case of 1 is 0 do external raise while in public class of object array else repeat until 1 is 0

Geändert von littleDave (10. Apr 2011 um 13:59 Uhr)
 
Benutzerbild von littleDave
littleDave

 
Delphi 7 Professional
 
#101
  Alt 16. Okt 2010, 14:47
Neue Version Version 0.5.5.0

Ich habe diesmal wieder einige Änderungen am Script-Code in der Script-System-Unit vorgenommen. Genauer gesagt habe ich die Convert-Klasse komplett neu geschrieben. Die Routinen "IntToStr", "IntToStrDef", usw. haben jetzt einen anderen Namen. Daher kann es zu notwendigen Anpassungen am Script-Quelltext kommen.

Die Benutzung der Convert-Klasse ist nun komplett an .NET angelehnt. Um einen String z.B. in einen Integer umzuwandeln, schreibt man nun System.Convert.ToInt32('12345'); . Die "ToInt32" gibt es dabei in sehr vielen überladenen Varianten, also z.B. für floats, strings mit Default-Wert, usw. Allgemein funktioniert die Konvert-Klasse wie folgt:

System.Convert.[Optional: Try]To[Ziel-Typ]([Quell-Typ])

wobei Ziel-Typ z.B. Int32, Int64, Single, Double, String, usw. ist.

Als positiven Ausgleich dafür habe ich die Performance der RunTime nochmal verbessert. Dadurch konnte die Auführungszeit von Scripten um bis zu 30% gesenkt werden.
  • Neuerungen
    • Neuer Typ: "System.UInt64"
    • Convert-Routinen für "System.UInt64"
    • Neue Op-Codes für das Laden von Integers, Floats, Strings und Pointer in den Stack -> großer Performanceschub in der RunTime
  • Änderungen
    • Die Convert-Klasse ist nun komplett neu erstellt. Daher heißen die Methoden-Namen nun anders, wodurch wahrscheinlich einige Anpassungen am Script-Quelltext nötig sein werden.
    • Verbesserungen des Optimizers im Linker. Durch neue Optimierungsstufen ist der Byte-Code und somit auch die Ausführgeschwindigkeit sehr verbessert worden.
    • Eine weitere Stufe zum Filtern der am besten passenden overloaded-Methode im Compiler eingebaut
  • Bug-Fixes
    • Das finden der besten überladenen Methode hatte ein Problem mit var-Parametern. Diese wurden nicht korrekt berücksichtigt.
    • Fehler beim automatischen generieren von Getter- und Setter-Methoden für properties in externen Klassen behoben
    • Fehler beim @-Statement für Methoden-Pointer, wenn kein "Self" mit angegeben wurde.

Download-Link ist im ersten Post.

Grüße
  Mit Zitat antworten Zitat
Benutzerbild von toms
toms

 
Delphi XE Professional
 
#102
  Alt 16. Okt 2010, 18:26
Im Indy+Thread Demo erhalte ich eine Fehlermeldung Could not add the unit "System.Xml" (Linie 5)
Thomas
  Mit Zitat antworten Zitat
Benutzerbild von littleDave
littleDave

 
Delphi 7 Professional
 
#103
  Alt 16. Okt 2010, 18:35
Du musst in der IDE die Packages "installieren". In den Packages sind die jeweiligen Units. Um das zu machen, musst du in der IDE im linken PageControl die Seite "Packages" öffnen. Dort sind alle "Package-DLLs" aufgelistet, die im Moment geladen sind. Einfach einen Rechtsklick und man kann weitere DLLs hinzufügen oder vorhandene entfernen. Um zu sehen, welche Unit in welchen Package ist, gibt es unten im PageControl mit den Seiten "Messages", "Debug Output", etc. einen weiteren Tab: "Registered Packages". Dort kann man sich dann alle Units der Packages anschauen.

Lange Rede, kurzer Sinn: füge im "Packages"-Tab die DLLs "libXML.dll" und "libIndy.dll" hinzu und schon sollte es gehen.
  Mit Zitat antworten Zitat
Benutzerbild von toms
toms

 
Delphi XE Professional
 
#104
  Alt 16. Okt 2010, 18:39
Lange Rede, kurzer Sinn: füge im "Packages"-Tab die DLLs "libXML.dll" und "libIndy.dll" hinzu und schon sollte es gehen.
Alles klar, vielen Dank.

PS: http://www.delphipraxis.net/rdf.php existiert nicht mehr.
Thomas
  Mit Zitat antworten Zitat
Benutzerbild von littleDave
littleDave

 
Delphi 7 Professional
 
#105
  Alt 16. Okt 2010, 19:01
Oh, danke für den Hinweis. Ich habe das Beispiel lange nicht mehr angeschaut - ich habe daher mal eine aktuelle Version erstellt. Einfach kopieren und im Editor einfügen.

Delphi-Quellcode:
program Project1;

uses
  System.Threading,
  System.Xml,
  Net.Indy;

type
  { Feed Query Data }
  TFeedQuery = record
  private
    FURL : string;
    FUsesUTF8 : boolean;
  public
    class function Create(URL: string; UsesUTF8: boolean): TFeedQuery;
  
    property URL : string read FURL;
    property UsesUTF8 : boolean read FUsesUTF8;
  end;
  
class function TFeedQuery.Create(URL: string; UsesUTF8: boolean): TFeedQuery;
begin
  result.FURL := URL;
  result.FUsesUTF8 := UsesUTF8;
end;

type
  { Execution Thread }
  TMyExecution = class(TExecutionContext)
  private
    FData : string;
    FError : boolean;
    FQuery : TFeedQuery;
  protected
    procedure Execute; override;
    function ExtractTitles: string;
  public
    constructor Create(Query: TFeedQuery); virtual;
  end;
  
constructor TMyExecution.Create(Query: TFeedQuery);
begin
  inherited Create;
  FQuery := Query;
end;

function TMyExecution.ExtractTitles: string;
var s: string;
    iStart, iStop: integer;
    tmp : string;
begin
  s := Self.FData;
  iStart := s.IndexOf('<title>');
  while iStart > 0 do
  begin
    iStop := s.IndexOf('</title>');
    if iStop > 0 then
    begin
      tmp := XML.Decode(s.Copy(iStart + string('<title>').Length, iStop - iStart - string('<title>').Length));
      if Self.FQuery.UsesUTF8 then
         result := result + StringEncoding.ToString(StringEncoding.AsUTF8(tmp)) + #13#10
      else
         result := result + tmp + #13#10;
      s := s.Copy(iStop + string('</title>').Length);
      iStart := s.IndexOf('<title>');
    end else
      iStart := 0;
  end;
end;

procedure TMyExecution.Execute;
var http: TIdHTTP;
begin
  http := TIdHTTP.Create;
  try
    http.HandleRedirects := True;
    try
      Self.FData := http.Get(Self.FQuery.URL);
      Self.FData := Self.FData
                   .Replace(#10, #13#10);
    except
      on e: EException do
      begin
        Self.FError := True;
        Self.FData := e.ToString;
      end;
    end;
    
  finally
    http.Free;
  end;
end;

function SelectFeedSource(var Query: TFeedQuery): boolean;
begin
  result := True;
  Console.WriteLine('Press [d] for Delphi, [s] for Spiegel, [h] for Heise, [esc] to cancel');
  while true do
  begin
    case Console.ReadKey.ToUpper of
    'D' :
      begin
        Query := TFeedQuery.Create('http://www.delphipraxis.net/external.php?type=RSS2', False);
        break;
      end;
    'S' :
      begin
        Query := TFeedQuery.Create('http://www.spiegel.de/schlagzeilen/tops/index.rss', False);
        break;
      end;
    'H' :
      begin
        Query := TFeedQuery.Create('http://www.heise.de/newsticker/heise.rdf', True);
        break;
      end;
    Strings.FromASCIIIndex(KeyCodes.Escape) :
      begin
        result := False;
        exit;
      end;
    end;
  end;
end;

{ Main APP }
var t : TThread;
    c : TMyExecution;
    Query : TFeedQuery;
begin
  if not SelectFeedSource(Query) then
     exit;
     
  repeat
    Console.Clear;
    c := TMyExecution.Create(Query);
    try
      t := TThread.NewThread(c);
      try
        t.Start;
        
        Console.WriteLine('Connecting ' + Query.URL);
        Console.Write('Waiting ');
        while (t.State <> ThreadState.Finished) do
        begin
          Console.Write('.');
          TThread.Sleep(100);
          TThread.Sleep(100);
          TThread.Sleep(50);
        end;
        Console.Clear;
        if c.FError then
        begin
          Console.ForegroundColor := Colors.Red;
          Console.WriteLine(c.FData);
          Console.ForegroundColor := Colors.White;
        end
        else
          Console.WriteLine(c.ExtractTitles);
      finally
        t.Free;
      end;
    finally
      c.Free;
    end;
    
    Console.WriteLine;
    if not SelectFeedSource(Query) then
       exit;
       
  until False;
end.
  Mit Zitat antworten Zitat
omata

 
Delphi 7 Enterprise
 
#106
  Alt 16. Okt 2010, 19:05
Wieso muss der Code so unschön sein?

Delphi-Quellcode:
{ Main APP }
:
:
begin
  while SelectFeedSource(Query) do begin
:
:
  end;
end.
  Mit Zitat antworten Zitat
Benutzerbild von littleDave
littleDave

 
Delphi 7 Professional
 
#107
  Alt 16. Okt 2010, 19:17
Weil es meine Programmiersprache ist (hast ja recht ...)
  Mit Zitat antworten Zitat
Benutzerbild von littleDave
littleDave

 
Delphi 7 Professional
 
#108
  Alt 28. Nov 2010, 16:47
Neue Version Version 0.6

Ist wurde mal wieder Zeit für einen größeren Versionssprung. Neu dabei ist unter anderem die for-in-Schleife, hier mal (wie immer) die Übersicht:
  • Neuerungen
    • Die for-in-Schleife ist nun im Script möglich. Der benötigte Enumerator und dessen Aufbau ist im PDF beschrieben.
    • Enumeratoren für TList, TStrings, TIntegerList, TInt64List und TFloatList hinzugefügt
    • Der Index von for-Schleifen kann jetzt lokal im Schleifenkopf definiert werden: for var i: integer := 0 to 10 do ;
    • Die Inhaltsvariable von for-in-Schleifen kann ebenfalls lokal definiert werden: for var s: string in AList do ;
    • Die Script-Engine kann jetzt mit direkten Funktionspointern zu externen Methoden umgehen. Das schaut z.B. so aus:
      Delphi-Quellcode:
      type
        TMyCallback = procedure(SomeArg: integer); external; // wichtig: muss als external definiert sein, stdcall etc. ist erlaubt

      function GetCallbackEntryPoint: Pointer; external; // liefert den direkten Funktionspointer

      var t: TMyCallback;
      begin
        t := GetCallbackEntryPoint;
        t(1234); // Funktion wird ausgeführt
      end;
    • DLL-Methoden können jetzt direkt im Script definiert und importiert werden. Die RunTime hat zudem ein eingebautes Sicherheitsfeature, mit dem gesteuert werden kann, ob eine Funktion importiert werden kann. Dies ist Standard-mäßig verboten, im PDF ist aber beschrieben, wie man das erlaubt.
      Delphi-Quellcode:
      procedure Sleep(dwMilliseconds: DWORD); external 'kernel32.dllname 'Sleep'; stdcall;

      begin
        Sleep(1000);
      end;
    • Neue Unit: System.Interop.Windows: Bietet die Klasse "TDynamicLinkLibrary" an, mit der man Funktionspointer aus DLLs dynamisch laden kann. Der gerade genannte Sicherheitsaspekt ist für diese Methode ebenfalls von Bedeutung.
      Delphi-Quellcode:
      uses
        System.Interop.Windows;

      type
        TSleep = procedure(dwMilliseconds: DWORD); external; stdcall;

      var Sleep: TSleep;
          Lib : TDynamicLinkLibrary;
      begin
        Lib := TDynamicLinkLibrary.Create('kernel32.dll');
        try
          Sleep := Lib.FindMethod('Sleep');
          if @Sleep <> nil then
             Sleep(1000);
        finally
          Lib.Free;
        end;
      end.
  • Änderungen
    • Compiler-Geschwindigkeit sowie Linker-Geschwindigkeit etwas verbessert
    • "exit", "break" oder "continue" ist jetzt innerhalb eines finally-end-Blockes verboten (wie in Delphi auch)
  • Bug-Fixes
    • try-except-Block und try-finally-Block komplett neu geschrieben. Es gab einige Probleme mit den Anweisungen "exit", "break" und "continue" innerhalb eines try-Blockes.
    • interne Größe von set-of-Typen hängt jetzt ebenfalls von der Anzahl der Elemente in der Aufzählung ab. Dies ist jetzt kompatibel zu Delphi, was vor allem in Records Probleme machen konnte
    • Compiler hat innerhalb es "uses"-Blockes das Script nicht korrekt validiert
    • Funktionsaufrufe mit Rückgabewert über einen Funktionspointer haben nicht korrekt funktioniert
    • Fehler in der RunTime beim OpCode "JIZ" und "JNZ" behoben

Download-Link ist im ersten Post.

Grüße
  Mit Zitat antworten Zitat
Florian Hämmerle
 
#109
  Alt 28. Nov 2010, 17:07
NICE (:

Freut mich zu hören, dass sich in der SE2 immer noch so viel tut. Weiter so (:
wenn das hier jetzt facebook wäre, würde ich mal "gefällt mir" klicken

mfg Florian
  Mit Zitat antworten Zitat
Benutzerbild von implementation
implementation

 
FreePascal / Lazarus
 
#110
  Alt 28. Nov 2010, 17:49
wenn das hier jetzt facebook wäre, würde ich mal "gefällt mir" klicken
Sowas sollte man hier wirklich mal einführen
Oder einen Danke-Button wie in der EE.
Marvin
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 11 von 12   « Erste     91011 12      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:43 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz