2024-02-02 05:57:46 +00:00
unit HCL;
{$mode objfpc} {$H+}
{$linklib hcl}
{$linklib c}
2024-02-18 01:12:56 +00:00
{$linklib dl}
{$linklib gcc}
2024-02-12 15:57:30 +00:00
{$if defined(HCL_LIB_QUADMATH_REQUIRED)}
2024-02-02 05:57:46 +00:00
{$linklib quadmath}
2024-02-12 15:57:30 +00:00
{$endif}
2024-02-02 05:57:46 +00:00
interface
2024-02-03 04:36:05 +00:00
type
2024-02-11 07:39:16 +00:00
BitMask = longword ; (* this must match hcl_bitmask_t in hcl.h *)
( * const
TRAIT_LANG_ENABLE_EOF = ( BitMask( 1 ) shl 1 4 ) ;
TRAIT_LANG_ENABLE_BLOCK = ( BitMask( 1 ) shl 1 5 ) ; * )
type
2024-02-12 15:57:30 +00:00
TraitBit = ( (* this enum must follow hcl_trait_t in hcl.h *)
2024-02-11 07:39:16 +00:00
LANG_ENABLE_EOF = ( BitMask( 1 ) shl 1 4 ) ,
LANG_ENABLE_BLOCK = ( BitMask( 1 ) shl 1 5 )
) ;
2024-02-12 15:57:30 +00:00
Option = ( (* this enum must follow hcl_option_t in hcl.h *)
2024-02-11 07:39:16 +00:00
TRAIT,
LOG_MASK,
LOG_MAXCAPA
) ;
2024-02-12 15:57:30 +00:00
IoCmd = ( (* this enum must follow hcl_io_cmd_t in hcl.h *)
IO_OPEN,
IO_CLOSE,
IO_READ,
IO_READ_BYTES,
IO_WRITE,
IO_WRITE_BYTES,
IO_FLUSH
) ;
2024-02-18 01:12:56 +00:00
{$packrecords c}
2024-02-12 15:57:30 +00:00
CciArgPtr = ^ CciArg;
CciArg = record (* this record must follow the public part of hcl_io_cciarg_t in hcl.h *)
name : pwidechar ;
handle: pointer ;
2024-02-17 00:16:44 +00:00
is_bytes: integer ;
2024-02-12 15:57:30 +00:00
buf: array [ 0 .. 2 0 4 7 ] of widechar ;
xlen: System. SizeUint;
includer: CciArgPtr;
end ;
2024-02-18 01:12:56 +00:00
{$packrecords normal}
2024-02-12 15:57:30 +00:00
2024-02-02 05:57:46 +00:00
Interp = class
2024-02-03 04:36:05 +00:00
protected
2024-02-02 05:57:46 +00:00
handle: pointer ;
2024-02-03 04:36:05 +00:00
2024-02-02 05:57:46 +00:00
public
2024-02-12 15:57:30 +00:00
constructor Create( x: integer ) ;
destructor Destroy( ) ; override ;
procedure Ignite( heapsize: System. SizeUint) ;
2024-02-02 05:57:46 +00:00
procedure AddBuiltinPrims( ) ;
2024-02-12 15:57:30 +00:00
procedure CompileFile( filename: pansichar ) ;
2024-02-02 05:57:46 +00:00
procedure Compile( text : pansichar ) ;
2024-02-12 15:57:30 +00:00
procedure Compile( text : pansichar ; len: System. SizeUint) ;
2024-02-02 05:57:46 +00:00
procedure Compile( text : pwidechar ) ;
2024-02-12 15:57:30 +00:00
procedure Compile( text : pwidechar ; len: System. SizeUint) ;
2024-02-02 05:57:46 +00:00
procedure Execute( ) ;
protected
function FetchErrorMsg( ) : string ;
end ;
2024-02-12 15:57:30 +00:00
IO = class
public
procedure Open( ) ; virtual ; abstract ;
procedure Close( ) ; virtual ; abstract ;
function Read( ) : System. SizeUint; virtual ; abstract ;
end ;
2024-02-03 04:36:05 +00:00
Location = record
2024-02-12 15:57:30 +00:00
line: System. SizeUint;
colm: System. SizeUint;
2024-02-03 04:36:05 +00:00
filp: pwidechar ;
end ;
Synerr = record
num: integer ;
loc: Location;
tgt: record
val: array [ 0 .. 2 5 5 ] of widechar ;
2024-02-12 15:57:30 +00:00
len: System. SizeUint;
2024-02-03 04:36:05 +00:00
end ;
end ;
SynerrPtr = ^ Synerr;
2024-02-02 05:57:46 +00:00
(*----- external hcl function -----*)
2024-02-12 15:57:30 +00:00
function hcl_errnum_to_errbcstr( errnum: integer ; errbuf: pointer ; errbufsz: System. SizeUint) : pointer ; cdecl ; external ;
2024-02-03 04:36:05 +00:00
function hcl_errnum_is_synerr( errnum: integer ) : boolean ; cdecl ; external ;
2024-02-12 15:57:30 +00:00
function hcl_openstd( xtnsize: System. SizeUint; errnum: pointer ) : pointer ; cdecl ; external ;
2024-02-02 05:57:46 +00:00
procedure hcl_close( handle: pointer ) ; cdecl ; external ;
2024-02-11 07:39:16 +00:00
function hcl_setoption( handle: pointer ; option: Option; value: pointer ) : integer ; cdecl ; external ;
function hcl_getoption( handle: pointer ; option: Option; value: pointer ) : integer ; cdecl ; external ;
2024-02-12 15:57:30 +00:00
procedure hcl_seterrnum ( handle: pointer ; errnum: integer ) ; cdecl ; external ;
2024-02-03 04:36:05 +00:00
function hcl_geterrnum( handle: pointer ) : integer ; cdecl ; external ;
2024-02-02 05:57:46 +00:00
function hcl_geterrbmsg( handle: pointer ) : pansichar ; cdecl ; external ;
2024-02-12 15:57:30 +00:00
function hcl_ignite( handle: pointer ; heapsize: System. SizeUint) : integer ; cdecl ; external ;
2024-02-02 05:57:46 +00:00
function hcl_addbuiltinprims( handle: pointer ) : integer ; cdecl ; external ;
function hcl_beginfeed( handle: pointer ; on_cnode: pointer ) : integer ; cdecl ; external ;
2024-02-12 15:57:30 +00:00
function hcl_feedbchars( handle: pointer ; data: pansichar ; len: System. SizeUint) : integer ; cdecl ; external ;
function hcl_feeduchars( handle: pointer ; data: pwidechar ; len: System. SizeUint) : integer ; cdecl ; external ; (* this is wrong in deed - hcl_uchar_t may not been widechar ..*)
2024-02-02 05:57:46 +00:00
function hcl_endfeed( handle: pointer ) : integer ; cdecl ; external ;
2024-02-12 15:57:30 +00:00
function hcl_attachccio( handle: pointer ; cci: pointer ) : integer ; cdecl ; external ;
2024-02-02 05:57:46 +00:00
function hcl_attachcciostdwithbcstr( handle: pointer ; cci: pansichar ) : integer ; cdecl ; external ;
procedure hcl_detachccio( handle: pointer ) ; cdecl ; external ;
function hcl_attachudiostdwithbcstr( handle: pointer ; udi: pansichar ; udo: pansichar ) : integer ; cdecl ; external ;
procedure hcl_detachudio( handle: pointer ) ; cdecl ; external ;
function hcl_compile( handle: pointer ; cnode: pointer ; flags: integer ) : integer ; cdecl ; external ;
2024-02-03 04:36:05 +00:00
function hcl_execute( handle: pointer ) : pointer ; cdecl ; external ;
2024-02-02 05:57:46 +00:00
procedure hcl_abort( handle: pointer ) cdecl ; external ;
2024-02-03 04:36:05 +00:00
procedure hcl_getsynerr( handle: pointer ; synerr: SynerrPtr) cdecl ; external ;
2024-02-12 15:57:30 +00:00
function hcl_count_ucstr( ptr: pwidechar ) : System. SizeUint; cdecl ; external ;
2024-02-02 05:57:46 +00:00
(*----- end external hcl function -----*)
implementation
2024-02-12 15:57:30 +00:00
uses SysUtils, Math, Classes;
2024-02-02 05:57:46 +00:00
constructor Interp. Create ( x: integer ) ;
2024-02-03 04:36:05 +00:00
var
2024-02-02 05:57:46 +00:00
h: pointer ;
errnum: integer ;
errmsg: array [ 0 .. 2 5 5 ] of AnsiChar ;
2024-02-11 07:39:16 +00:00
tb: BitMask;
2024-02-02 05:57:46 +00:00
begin
2024-02-11 07:39:16 +00:00
2024-02-02 05:57:46 +00:00
h : = hcl_openstd( 0 , @ errnum) ;
if h = nil then begin
2024-02-11 07:39:16 +00:00
hcl_errnum_to_errbcstr( errnum, @ errmsg, length( errmsg) ) ;
raise Exception. Create( errmsg) ;
end ;
tb : = BitMask( TraitBit. LANG_ENABLE_EOF) or BitMask( TraitBit. LANG_ENABLE_BLOCK) ;
if hcl_setoption( h, Option. TRAIT, @ tb) < = - 1 then begin
hcl_errnum_to_errbcstr( errnum, @ errmsg, length( errmsg) ) ;
hcl_close( h) ;
2024-02-02 05:57:46 +00:00
raise Exception. Create( errmsg) ;
end ;
self. handle : = h;
end ;
destructor Interp. Destroy;
begin
if self. handle < > nil then
begin
hcl_close( self. handle) ;
self. handle : = nil ;
end ;
inherited ;
end ;
function Interp. FetchErrorMsg( ) : string ;
var
2024-02-03 04:36:05 +00:00
num: integer ;
bmsg: pansichar ;
serr: Synerr;
filp: pwidechar ;
tgt: array [ 0 .. 2 5 5 ] of widechar ;
2024-02-02 05:57:46 +00:00
begin
2024-02-03 04:36:05 +00:00
num : = hcl_geterrnum( self. handle) ;
if hcl_errnum_is_synerr( num) then begin
hcl_getsynerr( self. handle, @ serr) ;
bmsg : = hcl_geterrbmsg( self. handle) ;
filp : = pwidechar( widestring( '' ) ) ;
if serr. loc. filp < > nil then filp : = serr. loc. filp;
if serr. tgt. len > 0 then begin
2024-02-12 15:57:30 +00:00
SysUtils. Strlcopy( @ tgt, serr. tgt. val, Math. Min( serr. tgt. len, length( tgt) - 1 ) ) ;
exit( SysUtils. Format( '%s at %s[%u:%u] - %s' , [ string( bmsg) , string( filp) , serr. loc. line, serr. loc. colm, string( tgt) ] ) ) ;
2024-02-03 04:36:05 +00:00
end
else begin
2024-02-12 15:57:30 +00:00
exit( SysUtils. Format( '%s at %s[%u:%u]' , [ string( bmsg) , string( filp) , serr. loc. line, serr. loc. colm] ) ) ;
2024-02-03 04:36:05 +00:00
end ;
end
else begin
bmsg : = hcl_geterrbmsg( self. handle) ;
exit( string( bmsg) )
end ;
2024-02-02 05:57:46 +00:00
end ;
2024-02-12 15:57:30 +00:00
procedure Interp. Ignite( heapsize: System. SizeUint) ;
2024-02-02 05:57:46 +00:00
begin
if hcl_ignite( self. handle, heapsize) < = - 1 then
begin
(* TODO: proper error message *)
raise Exception. Create( 'failed to ignite - ' + self. FetchErrorMsg( ) )
end ;
end ;
procedure Interp. AddBuiltinPrims( ) ;
begin
(* TODO: proper error message *)
if hcl_addbuiltinprims( self. handle) < = - 1 then
begin
raise Exception. Create( 'failed to add builtin primitives - ' + self. FetchErrorMsg( ) )
end ;
end ;
2024-02-12 15:57:30 +00:00
{$if 1}
function cci_handler( handle: pointer ; cmd: IoCmd; arg: CciArgPtr) : integer ; cdecl ;
var
f: System. THandle;
len: System. LongInt ;
begin
( * check if the main stream is requested.
* it doesn' t have to be handled because the main stream must be handled via feeding * )
2024-02-18 01:12:56 +00:00
2024-02-12 15:57:30 +00:00
if arg^ . includer = nil then exit( 0 ) ;
case cmd of
IO_OPEN: begin
2024-02-18 01:12:56 +00:00
(* TODO: remember the parent path and load from the parent directory if necessary*)
2024-02-12 15:57:30 +00:00
f : = SysUtils. FileOpen( arg^ . name , SysUtils. fmOpenRead) ;
if f < = - 1 then begin
// TODO: set error info....
exit( - 1 ) ;
end ;
arg^ . handle : = pointer( f) ;
2024-02-18 01:12:56 +00:00
arg^ . is_bytes : = 1 ;
2024-02-12 15:57:30 +00:00
end ;
IO_CLOSE: begin
f : = System. THandle( arg^ . handle) ;
SysUtils. FileClose( f) ;
end ;
IO_READ: begin
hcl_seterrnum( handle, 9 9 9 ) ; (* TODO: change error code to ENOIMPL *)
exit( - 1 ) ;
end ;
IO_READ_BYTES: begin
f : = System. THandle( arg^ . handle) ;
len : = SysUtils. FileRead( f, arg^ . buf, System. SizeOf( arg^ . buf) ) ;
if len < = - 1 then begin
// TODO: set error info
exit( - 1 ) ;
end ;
arg^ . xlen : = len;
end ;
IO_FLUSH:
(* no effect on an input stream *)
;
( * the following operations are prohibited on the code input stream:
IO_WRITE:
IO_WRITE_BYTES:
* )
else begin
hcl_seterrnum( handle, 9 9 9 ) ; (* TODO: change error code *)
exit( - 1 ) ;
end ;
end ;
exit( 0 ) ;
end ;
{$else}
function cci_handler( handle: pointer ; cmd: IoCmd; arg: CciArgPtr) : integer ; cdecl ;
var
f: Classes. TFileStream;
len: System. LongInt ;
begin
( * check if the main stream is requested.
* it doesn' t have to be handled because the main stream must be handled via feeding * )
if arg^ . includer = nil then exit( 0 ) ;
try
case cmd of
IO_OPEN: begin
f : = Classes. TFileStream. Create( arg^ . name , SysUtils. fmOpenRead) ;
arg^ . handle : = pointer( f) ;
end ;
IO_CLOSE: begin
f : = Classes. TFileStream( arg^ . handle) ;
f. Destroy( ) ;
end ;
IO_READ: begin
f : = Classes. TFileStream( arg^ . handle) ;
f. ReadBuffer( arg^ . buf, System. SizeOf( arg^ . buf) ) ;
if len < = - 1 then begin
// TODO: set error info
exit( - 1 ) ;
end ;
arg^ . xlen : = len;
end ;
IO_FLUSH:
(* no effect on an input stream *)
;
( * the following operations are prohibited on the code input stream:
IO_READ_BYTES:
IO_WRITE:
IO_WRITE_BYTES:
* )
else begin
hcl_seterrnum( handle, 9 9 9 ) ; (* TODO: change error code *)
exit( - 1 ) ;
end ;
end ;
except
on e: Exception do
writeln ( 'exception:' , e. Message ) ;
else
writeln ( 'unknonw exception' ) ;
exit( - 1 ) ;
end ;
exit( 0 ) ;
end ;
{$endif}
procedure Interp. CompileFile( filename: pansichar ) ;
var
f: System. THandle = - 1 ;
attached: boolean = false ;
feed_ongoing: boolean = false ;
errnum: System. Integer ;
errmsg: string ;
buf: array [ 0 .. 1 0 2 3 ] of ansichar ;
len: System. LongInt ;
label
oops;
begin
f : = SysUtils. FileOpen( filename, SysUtils. fmOpenRead) ;
if f < = - 1 then begin
errmsg : = 'failed to open file - ' + filename;
goto oops;
end ;
if hcl_attachccio( self. handle, @ cci_handler) < = - 1 then begin
errmsg : = 'failed to attach ccio handler - ' + self. FetchErrorMsg( ) ;
goto oops;
end ;
attached : = true ;
if hcl_beginfeed( self. handle, nil ) < = - 1 then begin
errmsg : = 'failed to begin feeding - ' + self. FetchErrorMsg( ) ;
goto oops;
end ;
feed_ongoing : = true ;
while true do begin
len : = SysUtils. FileRead( f, buf, System. SizeOf( buf) ) ;
if len < = - 1 then begin
errmsg : = 'failed to read file - ' + filename;
goto oops;
end ;
if len = 0 then break;
if hcl_feedbchars( self. handle, buf, len) < = - 1 then begin
errnum : = hcl_geterrnum( self. handle) ;
errmsg : = self. FetchErrorMsg( ) ;
if not hcl_errnum_is_synerr( errnum) then errmsg : = 'failed to feed text - ' + errmsg;
goto oops;
end ;
end ;
if hcl_endfeed( self. handle) < = - 1 then begin
errmsg : = 'failed to end feeding - ' + self. FetchErrorMsg( ) ;
goto oops;
end ;
feed_ongoing : = false ;
hcl_detachccio( self. handle) ;
SysUtils. FileClose( f) ;
exit( ) ;
oops:
if feed_ongoing then hcl_endfeed( self. handle) ;
if attached then hcl_detachccio( self. handle) ;
if f > = - 1 then SysUtils. FileClose( f) ;
raise Exception. Create( errmsg) ;
end ;
2024-02-02 05:57:46 +00:00
procedure Interp. Compile( text : pansichar ) ;
begin
2024-02-12 15:57:30 +00:00
self. Compile( text , SysUtils. Strlen( text ) ) ;
2024-02-02 05:57:46 +00:00
end ;
2024-02-12 15:57:30 +00:00
procedure Interp. Compile( text : pansichar ; len: System. SizeUint) ;
2024-02-02 05:57:46 +00:00
var
2024-02-03 04:36:05 +00:00
errnum: integer ;
2024-02-02 05:57:46 +00:00
errmsg: string ;
begin
2024-02-12 15:57:30 +00:00
if hcl_attachcciostdwithbcstr( self. handle, nil ) < = - 1 then
raise Exception. Create( 'failed to attach ccio handler - ' + self. FetchErrorMsg( ) ) ;
2024-02-02 05:57:46 +00:00
if hcl_beginfeed( self. handle, nil ) < = - 1 then begin
errmsg : = self. FetchErrorMsg( ) ;
hcl_detachccio( self. handle) ;
2024-02-12 15:57:30 +00:00
raise Exception. Create( 'failed to begin feeding - ' + errmsg) ;
2024-02-02 05:57:46 +00:00
end ;
2024-02-03 04:36:05 +00:00
2024-02-02 05:57:46 +00:00
if hcl_feedbchars( self. handle, text , len) < = - 1 then begin
2024-02-03 04:36:05 +00:00
errnum : = hcl_geterrnum( self. handle) ;
2024-02-02 05:57:46 +00:00
errmsg : = self. FetchErrorMsg( ) ;
hcl_endfeed( self. handle) ;
hcl_detachccio( self. handle) ;
2024-02-03 04:36:05 +00:00
if hcl_errnum_is_synerr( errnum) then
raise Exception. Create( errmsg)
else
raise Exception. Create( 'failed to feed text - ' + errmsg) ;
2024-02-02 05:57:46 +00:00
end ;
if hcl_endfeed( self. handle) < = - 1 then begin
errmsg : = self. FetchErrorMsg( ) ;
hcl_detachccio( self. handle) ;
raise Exception. Create( 'failed to end feeding - ' + errmsg)
end ;
hcl_detachccio( self. handle) ;
end ;
procedure Interp. Compile( text : pwidechar ) ;
begin
2024-02-12 15:57:30 +00:00
self. Compile( text , SysUtils. Strlen( text ) ) ;
2024-02-02 05:57:46 +00:00
end ;
2024-02-12 15:57:30 +00:00
procedure Interp. Compile( text : pwidechar ; len: System. SizeUint) ;
2024-02-02 05:57:46 +00:00
var
2024-02-03 04:36:05 +00:00
errnum: integer ;
2024-02-02 05:57:46 +00:00
errmsg: string ;
begin
2024-02-12 15:57:30 +00:00
if hcl_attachcciostdwithbcstr( self. handle, nil ) < = - 1 then
raise Exception. Create( 'failed to attach ccio handler - ' + self. FetchErrorMsg( ) ) ;
2024-02-02 05:57:46 +00:00
if hcl_beginfeed( self. handle, nil ) < = - 1 then begin
errmsg : = self. FetchErrorMsg( ) ;
hcl_detachccio( self. handle) ;
2024-02-12 15:57:30 +00:00
raise Exception. Create( 'failed to begin feeding - ' + errmsg) ;
2024-02-02 05:57:46 +00:00
end ;
if hcl_feeduchars( self. handle, text , len) < = - 1 then begin
2024-02-03 04:36:05 +00:00
errnum : = hcl_geterrnum( self. handle) ;
2024-02-02 05:57:46 +00:00
errmsg : = self. FetchErrorMsg( ) ;
hcl_endfeed( self. handle) ;
hcl_detachccio( self. handle) ;
2024-02-03 04:36:05 +00:00
if hcl_errnum_is_synerr( errnum) then
raise Exception. Create( errmsg)
2024-02-12 15:57:30 +00:00
else
2024-02-03 04:36:05 +00:00
raise Exception. Create( 'failed to feed text - ' + errmsg) ;
2024-02-02 05:57:46 +00:00
end ;
if hcl_endfeed( self. handle) < = - 1 then begin
errmsg : = self. FetchErrorMsg( ) ;
hcl_detachccio( self. handle) ;
raise Exception. Create( 'failed to end feeding - ' + errmsg)
end ;
hcl_detachccio( self. handle) ;
end ;
procedure Interp. Execute( ) ;
var
2024-02-03 04:36:05 +00:00
errmsg: string ;
2024-02-02 05:57:46 +00:00
begin
if hcl_attachudiostdwithbcstr( self. handle, nil , nil ) < = - 1 then begin
raise Exception. Create( 'failed to attach udio handlers - ' + self. FetchErrorMsg( ) )
end ;
2024-02-03 04:36:05 +00:00
if hcl_execute( self. handle) = nil then begin
errmsg : = self. FetchErrorMsg( ) ;
hcl_detachudio( self. handle) ;
raise Exception. Create( 'failed to execute - ' + errmsg)
2024-02-02 05:57:46 +00:00
end ;
2024-02-03 04:36:05 +00:00
hcl_detachudio( self. handle) ;
2024-02-02 05:57:46 +00:00
end ;
end . (* unit *)