end
# Returns null on success
- fun file_rename_to(dest: String): nullable String import String::to_cstring,
- NativeString::to_s, String as nullable `{
+ fun file_rename_to(dest: String): nullable String import String.to_cstring,
+ NativeString.to_s, String as nullable `{
int res = rename(String_to_cstring(recv), String_to_cstring(dest));
if (res == 0) return null_String();
return String_as_nullable(NativeString_to_s(strerror(errno)));
# Object method which will get a callback in wokeUp method, defined in MonkeyActionCallable interface
# Must be defined as Nit/C method because of C call inside
- fun wokeUpAction( toCall: MonkeyActionCallable, message: Object ) is extern import MonkeyActionCallable::wokeUp `{
+ fun wokeUpAction( toCall: MonkeyActionCallable, message: Object ) is extern import MonkeyActionCallable.wokeUp `{
// Allocating memory to keep reference of received parameters :
// - Object receiver
end
var ci = 0
- for c in self do
+ for c in self.chars do
var local_dispc
if c.override_dispc then
local_dispc = c
b = gets.to_i
printn "Operator (+, -, *, /, %): "
- op_char = gets[0]
+ op_char = gets.chars[0]
printn "Char to display: "
- disp_char = gets[0]
+ disp_char = gets.chars[0]
printn "Size of text: "
disp_size = gets.to_i
do
var inv_base64_chars = new HashMap[Char,Int]
for k in [0..base64_chars.length[ do
- inv_base64_chars[ base64_chars[k] ] = k
+ inv_base64_chars[ base64_chars.chars[k] ] = k
end
return inv_base64_chars
end
for s in [0..steps[ do
var e = 0
for ss in [0..3[ do
- e += self[s*3+ss].ascii.lshift((2-ss)*8)
+ e += self.chars[s*3+ss].ascii.lshift((2-ss)*8)
end
for ss in [0..4[ do
- result[s*4+3-ss] = base64_chars[ e.rshift(ss*6).bin_and( mask_6bit ) ]
+ result[s*4+3-ss] = base64_chars.chars[ e.rshift(ss*6).bin_and( mask_6bit ) ]
end
end
if chars_in_last_step == 1 then
- var e = self[length-1].ascii.lshift(16)
+ var e = self.chars[length-1].ascii.lshift(16)
for ss in [0..2[ do
- result[steps*4+1-ss] = base64_chars[ e.rshift((ss+2)*6).bin_and( mask_6bit ) ]
+ result[steps*4+1-ss] = base64_chars.chars[ e.rshift((ss+2)*6).bin_and( mask_6bit ) ]
end
else if chars_in_last_step == 2 then
- var e = self[length-2].ascii.lshift(16) +
- self[length-1].ascii.lshift(8)
+ var e = self.chars[length-2].ascii.lshift(16) +
+ self.chars[length-1].ascii.lshift(8)
for ss in [0..3[ do
- result[steps*4+2-ss] = base64_chars[ e.rshift((ss+1)*6).bin_and( mask_6bit ) ]
+ result[steps*4+2-ss] = base64_chars.chars[ e.rshift((ss+1)*6).bin_and( mask_6bit ) ]
end
end
for s in [0..steps[ do
var e = 0
for ss in [0..4[ do
- e += inverted_base64_chars[self[s*4+ss]].lshift((3-ss)*6)
+ e += inverted_base64_chars[self.chars[s*4+ss]].lshift((3-ss)*6)
end
for ss in [0..3[ do
if padding_count == 1 then
var e = 0
for ss in [0..3[ do
- e += inverted_base64_chars[self[s*4+ss]].lshift((3-ss)*6)
+ e += inverted_base64_chars[self.chars[s*4+ss]].lshift((3-ss)*6)
end
for ss in [0..2[ do
else if padding_count == 2 then
var e = 0
for ss in [0..2[ do
- e += inverted_base64_chars[self[s*4+ss]].lshift((3-ss)*6)
+ e += inverted_base64_chars[self.chars[s*4+ss]].lshift((3-ss)*6)
end
result[s*3] = e.rshift(2*8).bin_and( mask_8bit ).ascii
clear
return_home
var count = 0
- for c in v do
+ for c in v.chars do
if c == '\n' then
# FIXME, this should work
#write(true, "C0".to_hex)
# Internal method to set options to CURL using CURLSList parameter.
private fun i_setopt_slist(opt: CURLOption, list: CURLSList):CURLCode `{ return curl_easy_setopt( recv, opt, list); `}
# Internal method to set options to CURL using String parameter.
- private fun i_setopt_string(opt: CURLOption, str: String):CURLCode import String::to_cstring `{
+ private fun i_setopt_string(opt: CURLOption, str: String):CURLCode import String.to_cstring `{
char *rStr = String_to_cstring(str);
return curl_easy_setopt( recv, opt, rStr);
`}
return answ
end
# Internal method used to get String object information initially knowns as C Chars type
- private fun i_getinfo_chars(opt: CURLInfoChars, res: CURLInfoResponseString):CURLCode import CURLInfoResponseString::response=, NativeString::to_s_with_copy `{
+ private fun i_getinfo_chars(opt: CURLInfoChars, res: CURLInfoResponseString):CURLCode import CURLInfoResponseString.response=, NativeString.to_s_with_copy `{
char *r = NULL;
CURLcode c = curl_easy_getinfo( recv, opt, &r);
if((c == CURLE_OK) && r != NULL){
return answ
end
# Internal method used to get Int object information initially knowns as C Long type
- private fun i_getinfo_long(opt: CURLInfoLong, res: CURLInfoResponseLong):CURLCode import CURLInfoResponseLong::response= `{
+ private fun i_getinfo_long(opt: CURLInfoLong, res: CURLInfoResponseLong):CURLCode import CURLInfoResponseLong.response= `{
long *r = NULL;
r = malloc(sizeof(long));
CURLcode c = curl_easy_getinfo( recv, opt, r);
return answ
end
# Internal method used to get Int object information initially knowns as C Double type
- private fun i_getinfo_double(opt: CURLInfoDouble, res: CURLInfoResponseDouble):CURLCode import CURLInfoResponseDouble::response= `{
+ private fun i_getinfo_double(opt: CURLInfoDouble, res: CURLInfoResponseDouble):CURLCode import CURLInfoResponseDouble.response= `{
double *r = NULL;
r = malloc(sizeof(double));
CURLcode c = curl_easy_getinfo( recv, opt, r);
return answ
end
# Internal method used to get Array[String] object information initially knowns as C SList type
- private fun i_getinfo_slist(opt: CURLInfoSList, res: CURLInfoResponseArray):CURLCode import CURLInfoResponseArray::prim_response=`{
+ private fun i_getinfo_slist(opt: CURLInfoSList, res: CURLInfoResponseArray):CURLCode import CURLInfoResponseArray.prim_response=`{
struct curl_slist* csl = NULL;
CURLcode ce = curl_easy_getinfo( recv, opt, &csl);
CURLInfoResponseArray_prim_response__assign(res, csl);
return once new CURLCode.unknown_option
end
# Internal method used to configure read callback
- private fun i_register_read_datas_callback(delegate: CCurlCallbacks, datas: String, size: Int):CURLCode import String::to_cstring `{
+ private fun i_register_read_datas_callback(delegate: CCurlCallbacks, datas: String, size: Int):CURLCode import String.to_cstring `{
CURLCallbackReadDatas *d = NULL;
d = malloc(sizeof(CURLCallbackReadDatas));
d->data = (char*)String_to_cstring(datas);
return curl_easy_setopt( recv, CURLOPT_READDATA, d);
`}
# Internal method used to configure callbacks in terms of given type
- private fun i_register_callback(delegate: CCurlCallbacks, cbtype: CURLCallbackType):CURLCode is extern import CCurlCallbacks::header_callback, CCurlCallbacks::body_callback, CCurlCallbacks::stream_callback `{
+ private fun i_register_callback(delegate: CCurlCallbacks, cbtype: CURLCallbackType):CURLCode is extern import CCurlCallbacks.header_callback, CCurlCallbacks.body_callback, CCurlCallbacks.stream_callback `{
CURLCallbackDatas *d = malloc(sizeof(CURLCallbackDatas));
CCurlCallbacks_incr_ref(delegate);
d->type = cbtype;
return e;
`}
# Convert given string to URL encoded string
- fun escape(url: String):String import String::to_cstring, NativeString::to_s_with_copy `{
+ fun escape(url: String):String import String.to_cstring, NativeString.to_s_with_copy `{
char *orig_url, *encoded_url = NULL;
orig_url = String_to_cstring(url);
encoded_url = curl_easy_escape( recv, orig_url, strlen(orig_url));
fun is_valid_protocol:Bool `{ return recv == CURLE_UNSUPPORTED_PROTOCOL; `}
fun is_valid_init:Bool `{ return recv == CURLE_FAILED_INIT; `}
fun to_i:Int do return code end
- redef fun to_s import NativeString::to_s_with_copy `{
+ redef fun to_s import NativeString.to_s_with_copy `{
char *c = (char*)curl_easy_strerror(recv);
return NativeString_to_s_with_copy(c);
`}
# Empty constructor which allow us to avoid the use of Nit NULLABLE type
private new `{ return NULL; `}
# Constructor allow us to get list instancied by appending an element inside.
- new with_str(s: String) import String::to_cstring `{
+ new with_str(s: String) import String.to_cstring `{
struct curl_slist *l = NULL;
l = curl_slist_append(l, String_to_cstring(s));
return l;
# Check for initialization
fun is_init:Bool `{ return (recv != NULL); `}
# Append an element in the linked list
- fun append(key: String) import String::to_cstring `{
+ fun append(key: String) import String.to_cstring `{
char *k = String_to_cstring(key);
curl_slist_append(recv, (char*)k);
`}
end
end
-# Array Response type of CCurl::easy_getinfo method
+# Array Response type of CCurl.easy_getinfo method
class CURLInfoResponseArray
var response:Array[String] = new Array[String]
private var prim_response:CURLSList = new CURLSList
end
-# Long Response type of CCurl::easy_getinfo method
+# Long Response type of CCurl.easy_getinfo method
class CURLInfoResponseLong
var response:Int=0
end
-# Double Response type of CCurl::easy_getinfo method
+# Double Response type of CCurl.easy_getinfo method
class CURLInfoResponseDouble
var response:Int=0
end
var response:String = ""
end
-# Reproduce Enum of available CURL SList information, used for CCurl::easy_getinfo
+# Reproduce Enum of available CURL SList information, used for CCurl.easy_getinfo
extern CURLInfoSList `{ CURLINFO `}
new ssl_engines `{ return CURLINFO_SSL_ENGINES; `}
new cookielist `{ return CURLINFO_COOKIELIST; `}
end
-# Reproduce Enum of available CURL Long information, used for CCurl::easy_getinfo
+# Reproduce Enum of available CURL Long information, used for CCurl.easy_getinfo
extern CURLInfoLong `{ CURLINFO `}
new response_code `{ return CURLINFO_RESPONSE_CODE; `}
new header_size `{ return CURLINFO_HEADER_SIZE; `}
new rtsp_cseq_recv `{ return CURLINFO_RTSP_CSEQ_RECV; `}
end
-# Reproduce Enum of available CURL Double information, used for CCurl::easy_getinfo
+# Reproduce Enum of available CURL Double information, used for CCurl.easy_getinfo
extern CURLInfoDouble `{ CURLINFO `}
new total_time `{ return CURLINFO_TOTAL_TIME; `}
new namelookup_time `{ return CURLINFO_NAMELOOKUP_TIME; `}
new content_length_upload `{ return CURLINFO_CONTENT_LENGTH_UPLOAD; `}
end
-# Reproduce Enum of available CURL Chars information, used for CCurl::easy_getinfo
+# Reproduce Enum of available CURL Chars information, used for CCurl.easy_getinfo
extern CURLInfoChars `{ CURLINFO `}
new content_type `{ return CURLINFO_CONTENT_TYPE; `}
new effective_url `{ return CURLINFO_EFFECTIVE_URL; `}
fun to_i:Int `{ return recv; `}
end
-# Reproduce Enum of CURL Options usable, used for CCurl::easy_setopt
+# Reproduce Enum of CURL Options usable, used for CCurl.easy_setopt
extern CURLOption `{ CURLoption `}
new write_function `{ return CURLOPT_WRITEFUNCTION; `}
new write_data `{ return CURLOPT_WRITEDATA; `}
# print a string somewhere
# NOTE: as with the curses API, the position is (y,x)
- fun mvaddstr(y,x: Int, str: String) import String::to_cstring `{
+ fun mvaddstr(y,x: Int, str: String) import String.to_cstring `{
char *c_string = String_to_cstring( str );
mvaddstr(y, x, c_string);
`}
return NativeString_to_s( (char *)gtk_assistant_get_page_title( recv, page ) );
`}
- fun set_page_title( page : GtkWidget, title : String) is extern import String::to_cstring`{
+ fun set_page_title( page : GtkWidget, title : String) is extern import String.to_cstring `{
gtk_assistant_set_page_title( recv, page, String_to_cstring( title ) );
`}
extern GtkWidget `{GtkWidget *`}
fun show_all is extern `{ gtk_widget_show_all( recv ); `}
- fun signal_connect( signal_name : String, to_call : GtkCallable, user_data : nullable Object ) is extern import String::to_cstring, GtkCallable::signal, Object as not nullable `{
+ fun signal_connect( signal_name : String, to_call : GtkCallable, user_data : nullable Object ) is extern import String.to_cstring, GtkCallable.signal, Object as not nullable `{
NitGtkSignal *data = malloc( sizeof(NitGtkSignal) );
GtkCallable_incr_ref( to_call );
return win;
`}
- fun title=( title : String ) is extern import String::to_cstring `{
+ fun title=( title : String ) is extern import String.to_cstring `{
gtk_window_set_title( recv, String_to_cstring( title ) );
`}
extern GtkFrame `{GtkFrame *`}
super GtkBin
- new ( lbl : String ) is extern import String::to_cstring`{
+ new ( lbl : String ) is extern import String.to_cstring`{
return (GtkFrame *)gtk_frame_new( String_to_cstring( lbl ) );
`}
return NativeString_to_s( (char *)gtk_frame_get_label( recv ) );
`}
- fun frame_label=( lbl : String ) is extern import String::to_cstring`{
+ fun frame_label=( lbl : String ) is extern import String.to_cstring`{
gtk_frame_set_label( recv, String_to_cstring( lbl ) );
`}
return (GtkEntry *)gtk_entry_new();
`}
- fun text : String is extern import String::to_cstring`{
+ fun text : String is extern import String.to_cstring`{
return NativeString_to_s( (char *)gtk_entry_get_text( recv ) );
`}
- fun text=( value : String) is extern import String::to_cstring`{
+ fun text=( value : String) is extern import String.to_cstring`{
gtk_entry_set_text( recv, String_to_cstring( value ) );
`}
gtk_scale_set_has_origin( recv, orig );
`}
- fun add_mark( value : Float, position : GtkPositionType, markup : String ) is extern import String::to_cstring`{
+ fun add_mark( value : Float, position : GtkPositionType, markup : String ) is extern import String.to_cstring`{
gtk_scale_add_mark( recv, value, position, String_to_cstring( markup ) );
`}
super GtkMisc
# Create a GtkLabel with text
- new ( text : String ) is extern import String::to_cstring `{
+ new ( text : String ) is extern import String.to_cstring `{
return (GtkLabel*)gtk_label_new( String_to_cstring( text ) );
`}
# Set the text of the label
- fun text=( text : String ) import String::to_cstring `{
+ fun text=( text : String ) import String.to_cstring `{
gtk_label_set_text( recv, String_to_cstring( text ) );
`}
# Returns the text of the label
- fun text : String import NativeString::to_s `{
+ fun text : String import NativeString.to_s `{
return NativeString_to_s( (char*)gtk_label_get_text( recv ) );
`}
`}
# Create a GtkImage with text
- new file( filename : String ) is extern import String::to_cstring `{
+ new file( filename : String ) is extern import String.to_cstring `{
return (GtkImage*)gtk_image_new_from_file( String_to_cstring( filename ) );
`}
`}
#Create a GtkButton with text
- new with_label( text : String ) is extern import String::to_cstring `{
+ new with_label( text : String ) is extern import String.to_cstring `{
return (GtkButton *)gtk_button_new_with_label( String_to_cstring( text ) );
`}
- new from_stock( stock_id : String ) is extern import String::to_cstring `{
+ new from_stock( stock_id : String ) is extern import String.to_cstring `{
return (GtkButton *)gtk_button_new_from_stock( String_to_cstring( stock_id ) );
`}
return NativeString_to_s( (char *)gtk_button_get_label( recv ) );
`}
- fun text=( value : String ) is extern import String::to_cstring`{
+ fun text=( value : String ) is extern import String.to_cstring`{
gtk_button_set_label( recv, String_to_cstring( value ) );
`}
extern GtkLinkButton `{GtkLinkButton *`}
super GtkButton
- new( uri: String ) is extern import String::to_cstring `{
+ new( uri: String ) is extern import String.to_cstring `{
return (GtkLinkButton *)gtk_link_button_new( String_to_cstring(uri) );
`}
end
extern GtkExpander `{GtkExpander *`}
super GtkBin
- new( lbl : String) is extern import String::to_cstring`{
+ new( lbl : String) is extern import String.to_cstring`{
return (GtkExpander *)gtk_expander_new( String_to_cstring( lbl ) );
`}
- new with_mnemonic( lbl : String) is extern import String::to_cstring`{
+ new with_mnemonic( lbl : String) is extern import String.to_cstring`{
return (GtkExpander *)gtk_expander_new_with_mnemonic(String_to_cstring( lbl ));
`}
return NativeString_to_s( (char *)gtk_expander_get_label( recv ) );
`}
- fun label_text=( lbl : String ) is extern import String::to_cstring`{
+ fun label_text=( lbl : String ) is extern import String.to_cstring`{
gtk_expander_set_label( recv, String_to_cstring( lbl ) );
`}
return NativeString_to_s( (char *)gtk_combo_box_get_active_id( recv ) );
`}
- fun active_id=( id_active : String ) is extern import String::to_cstring`{
+ fun active_id=( id_active : String ) is extern import String.to_cstring`{
gtk_combo_box_set_active_id( recv, String_to_cstring( id_active ) );
`}
return NativeString_to_s( (char *)gtk_combo_box_get_title( recv ) );
`}
- fun title=( t : String ) is extern import String::to_cstring`{
+ fun title=( t : String ) is extern import String.to_cstring `{
gtk_combo_box_set_title( recv, String_to_cstring( t ) );
`}
return (GtkDialog *)gtk_dialog_new( );
`}
- new with_buttons( title : String, parent : GtkWindow, flags : GtkDialogFlags) is extern import String::to_cstring`{
+ new with_buttons( title : String, parent : GtkWindow, flags : GtkDialogFlags) is extern import String.to_cstring`{
return (GtkDialog *)gtk_dialog_new_with_buttons( String_to_cstring( title ), parent, flags, "", NULL );
`}
return NativeString_to_s( (char *)gtk_about_dialog_get_program_name( recv ) );
`}
- fun program_name=( name : String ) is extern import String::to_cstring`{
+ fun program_name=( name : String ) is extern import String.to_cstring`{
gtk_about_dialog_set_program_name( recv, String_to_cstring( name ) );
`}
return NativeString_to_s( (char *)gtk_about_dialog_get_version( recv ) );
`}
- fun version=( v : String ) is extern import String::to_cstring`{
+ fun version=( v : String ) is extern import String.to_cstring`{
gtk_about_dialog_set_version( recv, String_to_cstring( v ) );
`}
return NativeString_to_s( (char *)gtk_about_dialog_get_copyright( recv ) );
`}
- fun copyright=( c : String ) is extern import String::to_cstring`{
+ fun copyright=( c : String ) is extern import String.to_cstring`{
gtk_about_dialog_set_copyright( recv, String_to_cstring( c ) );
`}
return NativeString_to_s( (char *)gtk_about_dialog_get_comments( recv ) );
`}
- fun comments=( com : String ) is extern import String::to_cstring`{
+ fun comments=( com : String ) is extern import String.to_cstring`{
gtk_about_dialog_set_comments( recv, String_to_cstring( com ) );
`}
return NativeString_to_s( (char *)gtk_about_dialog_get_license( recv ) );
`}
- fun license=( li : String ) is extern import String::to_cstring`{
+ fun license=( li : String ) is extern import String.to_cstring`{
gtk_about_dialog_set_license( recv, String_to_cstring( li ) );
`}
return NativeString_to_s( (char *)gtk_about_dialog_get_website( recv ) );
`}
- fun website=( link : String ) is extern import String::to_cstring`{
+ fun website=( link : String ) is extern import String.to_cstring`{
gtk_about_dialog_set_website( recv, String_to_cstring( link ) );
`}
return NativeString_to_s( (char *) gtk_about_dialog_get_website_label( recv ) );
`}
- fun website_label=( link_label : String ) is extern import String::to_cstring`{
+ fun website_label=( link_label : String ) is extern import String.to_cstring`{
gtk_about_dialog_set_website_label( recv, String_to_cstring( link_label ) );
`}
#`}
#TODO
- #fun authors=( authors_list : String ) is extern import String::to_cstring`{
+ #fun authors=( authors_list : String ) is extern import String.to_cstring`{
# gtk_about_dialog_set_authors( recv, String_to_cstring( authors_list ) );
#`}
- fun show ( parent : GtkWindow, params : String ) is extern import String::to_cstring`{
+ fun show ( parent : GtkWindow, params : String ) is extern import String.to_cstring`{
gtk_show_about_dialog( parent, String_to_cstring( params ), NULL);
`}
end
# return (GtkAppChooserDialog *)gtk_app_chooser_dialog_new( parent, flags, file );
#`}
- new for_content_type ( parent : GtkWindow, flags : GtkDialogFlags, content_type : String ) is extern import String::to_cstring `{
+ new for_content_type ( parent : GtkWindow, flags : GtkDialogFlags, content_type : String ) is extern import String.to_cstring `{
return (GtkAppChooserDialog *)gtk_app_chooser_dialog_new_for_content_type( parent, flags, String_to_cstring( content_type ) );
`}
return NativeString_to_s( (char *)gtk_app_chooser_dialog_get_heading( recv ) );
`}
- fun heading=( text : String ) is extern import String::to_cstring `{
+ fun heading=( text : String ) is extern import String.to_cstring `{
gtk_app_chooser_dialog_set_heading( recv, String_to_cstring( text ) );
`}
extern GtkColorChooserDialog `{GtkColorChooserDialog *`}
super GtkDialog
- new ( title : String, parent : GtkWindow ) is extern import String::to_cstring `{
+ new ( title : String, parent : GtkWindow ) is extern import String.to_cstring `{
return (GtkColorChooserDialog *)gtk_color_chooser_dialog_new( String_to_cstring( title ), parent );
`}
end
extern GtkFileChooserDialog `{GtkFileChooserDialog *`}
super GtkDialog
- new ( title : String, parent : GtkWindow, action : GtkFileChooserAction ) is extern import String::to_cstring `{
+ new ( title : String, parent : GtkWindow, action : GtkFileChooserAction ) is extern import String.to_cstring `{
return (GtkFileChooserDialog *)gtk_file_chooser_dialog_new( String_to_cstring( title ), parent, action, "", NULL );
`}
end
extern GtkMessageDialog `{GtkMessageDialog *`}
super GtkDialog
- new ( parent : GtkWindow, flags : GtkDialogFlags, msg_type : GtkMessageType, btn_type : GtkButtonsType, format : String ) is extern import String::to_cstring `{
+ new ( parent : GtkWindow, flags : GtkDialogFlags, msg_type : GtkMessageType, btn_type : GtkButtonsType, format : String ) is extern import String.to_cstring `{
return (GtkMessageDialog *)gtk_message_dialog_new( parent, flags, msg_type, btn_type, String_to_cstring( format ), NULL );
`}
end
gtk_progress_bar_set_show_text( recv, show );
`}
- fun text : String is extern import String::to_cstring`{
+ fun text : String is extern import String.to_cstring`{
return NativeString_to_s( (char *)gtk_progress_bar_get_text( recv ) );
`}
- fun text=( value : String) is extern import String::to_cstring`{
+ fun text=( value : String) is extern import String.to_cstring`{
gtk_progress_bar_set_text( recv, String_to_cstring( value ) );
`}
extern GtkColorSelectionDialog
super GtkWidget
- new ( title : String, parent : GtkWindow ) is extern import String::to_cstring `{
+ new ( title : String, parent : GtkWindow ) is extern import String.to_cstring `{
return gtk_color_chooser_dialog_new( String_to_cstring( title ), parent );
`}
intrude import jsonable
+in "C Header" `{
+ #define __STRICT_ANSI__
+ #include <json/json.h>
+`}
+
redef class String
# Deserializes this String and return its value as a Map[String, nullable Jsonable]
# On error, null is returned.
- fun json_to_object : nullable Map[String, nullable Jsonable] import NativeString::to_s, JsonObject::json_to_map `{
+ fun json_to_object : nullable Map[String, nullable Jsonable] import NativeString.to_s, JsonObject.json_to_map `{
char *native_recv;
json_object *jobj;
- nullable_Map map;
+ nullable_Map_of_String_nullable_Jsonable map;
native_recv = String_to_cstring( recv );
jobj = json_tokener_parse( native_recv );
redef extern JsonObject
# Get this json object as a Map
- private fun json_to_map : nullable Map[String, nullable Jsonable] import NativeString::to_s, String::to_cstring, HashMap, HashMap::[]=, json_cross, HashMap[String,nullable Jsonable] as( nullable Map[String,nullable Jsonable] ), String as ( Object ), nullable Jsonable as (nullable Object) `{
- HashMap map;
+ private fun json_to_map : nullable Map[String, nullable Jsonable] import NativeString.to_s, String.to_cstring, HashMap[String,nullable Jsonable], HashMap[String,nullable Jsonable].[]=, json_cross, HashMap[String, nullable Jsonable].as(nullable Map[String, nullable Jsonable]) `{
+ HashMap_of_String_nullable_Jsonable map;
String nit_key;
nullable_Jsonable nit_val;
enum json_type type;
- map = new_HashMap();
+ map = new_HashMap_of_String_nullable_Jsonable();
{ /* prevents "mixed declaration and code" warning for C90 */
json_object_object_foreach( recv, key, val ) {
nit_val = JsonObject_json_cross( val, type );
- HashMap__index_assign( map, String_as_Object( nit_key ), nullable_Jsonable_as_nullable_Object( nit_val ) );
+ HashMap_of_String_nullable_Jsonable__index_assign( map, nit_key, nit_val );
}
}
- return HashMap_as_nullable_Map( map );
+ return HashMap_of_String_nullable_Jsonable_as_nullable_Map_of_String_nullable_Jsonable( map );
`}
# Get this json object as a Bool
`}
# Get this json object as a Sequence
- private fun json_to_sequence : Sequence[Jsonable] import Array, Array::push, Array[nullable Jsonable] as ( Sequence[nullable Jsonable] ), json_cross `{
+ private fun json_to_sequence : Sequence[nullable Jsonable] import Array[nullable Jsonable], Array[nullable Jsonable].push, json_cross, Array[nullable Jsonable].as(Sequence[nullable Jsonable]) `{
array_list* jlist;
json_object* jobj;
nullable_Jsonable obj;
- Array dest;
+ Array_of_nullable_Jsonable dest;
int i;
int len;
enum json_type type;
jlist = json_object_get_array( recv );
len = json_object_array_length( recv );
- dest = new_Array();
+ dest = new_Array_of_nullable_Jsonable();
for ( i = 0; i < len; i ++ ) {
jobj = json_object_array_get_idx( recv, i );
if ( jobj == NULL ) type = json_type_null;
else type = json_object_get_type( jobj );
obj = JsonObject_json_cross( jobj, type );
- Array_push( dest, nullable_Jsonable_as_nullable_Object( obj ) );
+ Array_of_nullable_Jsonable_push( dest, obj );
}
- return Array_as_Sequence( dest );
+ return Array_of_nullable_Jsonable_as_Sequence_of_nullable_Jsonable( dest );
`}
# Get this json object as a String
- private fun json_to_string : String import NativeString::to_s `{
+ private fun json_to_string : String import NativeString.to_s `{
const char *cstring;
cstring = json_object_get_string( recv );
return NativeString_to_s( (char*)cstring );
intrude import jsonable
+in "C Header" `{
+ #define __STRICT_ANSI__
+ #include <json/json.h>
+`}
+
redef interface Jsonable
# Get a JsonObject representing this instance, specific to the C library
private fun to_json_object : JsonObject is abstract
const char *json_native_string;
String json_string;
- jobj = Map_to_json_object( recv );
+ jobj = Map_of_Object_nullable_Object_to_json_object( recv );
#ifdef JSON_C_TO_STRING_PRETTY
if ( pretty )
json_native_string = json_object_to_json_string_ext( jobj, JSON_C_TO_STRING_PRETTY );
end
redef class String
- redef fun to_json_object import NativeString::to_s `{
+ redef fun to_json_object import NativeString.to_s `{
char *native_recv = String_to_cstring( recv );
return json_object_new_string( native_recv );
`}
new `{ return json_object_new_object(); `}
# Add a key and value to the object
- fun add( key : String, val : nullable JsonObject ) import String::to_cstring, nullable JsonObject as not nullable `{
+ fun add( key : String, val : nullable JsonObject ) import String.to_cstring, JsonObject as not nullable `{
char* native_key;
native_key = String_to_cstring( key );
- if ( JsonObject_is_null(val) ) {
+ if ( nullable_JsonObject_is_null(val) ) {
json_object_object_add( recv, native_key, NULL );
} else {
json_object *jobj;
- jobj = JsonObject_as_not_null( val );
+ jobj = nullable_JsonObject_as_JsonObject( val );
json_object_object_add( recv, native_key, jobj );
}
`}
new `{ return json_object_new_array(); `}
fun push( val : nullable JsonObject ) `{
- if ( JsonObject_is_null(val) )
+ if ( nullable_JsonObject_is_null(val) )
json_object_array_add( recv, NULL );
else
- json_object_array_add( recv, JsonObject_as_not_null(val) );
+ json_object_array_add( recv, nullable_JsonObject_as_JsonObject(val) );
`}
end
end
# Main object type used by C library
-private extern JsonObject `{ json_object* `}
+private extern JsonObject `{ struct json_object* `}
# Give up ownership of this object and decrease the reference count.
fun put `{ json_object_put( recv ); `}
redef class String
# returns the md5 digest of the receiver string
# algorithm implemented by L. Peter Deutsch <ghost@aladdin.com>
- fun md5: String import String::to_cstring, NativeString::to_s, String::print `{
+ fun md5: String import String.to_cstring, NativeString.to_s, String.print `{
md5_state_t state;
md5_byte_t digest[16]; /* result */
char *hex_output = malloc(33*sizeof(char));
redef fun blended: Bool is extern `{ return recv->blended; `}
# inherits scale and blend from source
- redef fun subimage( x, y, w, h: Int ): Image is extern import Opengles1Image as ( Image ) `{
+ redef fun subimage( x, y, w, h: Int ): Image is extern import Opengles1Image.as( Image ) `{
struct mnit_opengles_Texture* image =
malloc( sizeof( struct mnit_opengles_Texture ) );
`}
# using sdl
- new from_file( path: String ) is extern import String::to_cstring `{
+ new from_file( path: String ) is extern import String.to_cstring `{
SDL_Surface *sdl_image;
struct mnit_opengles_Texture *opengles_image;
return events
end
- private fun poll_event: nullable IE is extern import SDLKeyEvent, SDLMouseButtonEvent, SDLMouseMotionEvent, SDLQuitEvent, NativeString::to_s, SDLMouseButtonEvent as (nullable IE), SDLMouseMotionEvent as (nullable IE), SDLKeyEvent as (nullable IE), SDLQuitEvent as (nullable IE) `{
+ private fun poll_event: nullable IE is extern import SDLKeyEvent, SDLMouseButtonEvent, SDLMouseMotionEvent, SDLQuitEvent, NativeString.to_s, SDLMouseButtonEvent.as(nullable IE), SDLMouseMotionEvent.as(nullable IE), SDLKeyEvent.as(nullable IE), SDLQuitEvent.as(nullable IE) `{
SDL_Event event;
SDL_PumpEvents();
super DrawableImage
super SDLDrawable
- # Import image from a file
- new from_file( path: String ) is extern import String::to_cstring `{
+ # Import image from a file
+ new from_file( path: String ) is extern import String.to_cstring `{
SDL_Surface *image = IMG_Load( String_to_cstring( path ) );
return image;
`}
return new_image;
`}
- # Save the image into the specified file
+ # Save the image into the specified file
fun save_to_file( path: String ) is extern import String::to_cstring `{ `}
# Destroy the image and free the memory
redef fun to_c: nullable Char
do
- if key_name.length == 1 then return key_name.first
+ if key_name.length == 1 then return key_name.chars.first
return null
end
# Class to load and use TTF_Font
extern SDLFont in "C" `{TTF_Font *`}
- #Load a font with a specified name and size
- new ( name: String, points: Int ) is extern import String::to_cstring `{
+ # Load a font with a specified name and size
+ new ( name: String, points: Int ) is extern import String.to_cstring `{
char * cname = String_to_cstring( name );
TTF_Font *font = TTF_OpenFont( cname, (int)points);
`}
fun destroy is extern `{ TTF_CloseFont( recv ); `}
- #Create a String with the specified color, return an SDLImage
- fun render( text: String, r, g, b: Int ): SDLImage is extern import String::to_cstring `{
+
+ # Create a String with the specified color, return an SDLImage
+ fun render( text: String, r, g, b: Int ): SDLImage is extern import String.to_cstring `{
SDL_Color color;
SDL_Surface *text_surface;
char *ctext;
return TTF_FontDescent( recv );
`}
- # Get the recommended pixel height of a rendered line of text of the loaded font. This is usually larger than the Font::height.
+ # Get the recommended pixel height of a rendered line of text of the loaded font. This is usually larger than the Font.height.
fun line_skip: Int is extern `{
return TTF_FontLineSkip( recv );
`}
`}
# Return the family name of the font
- fun family_name: nullable String is extern import String::to_cstring, String as nullable `{
+ fun family_name: nullable String is extern import String.to_cstring, String as nullable `{
char *fn = TTF_FontFaceFamilyName( recv );
if ( fn == NULL )
`}
# Return the style name of the font
- fun style_name: nullable String is extern import String::to_cstring, String as nullable `{
+ fun style_name: nullable String is extern import String.to_cstring, String as nullable `{
char *sn = TTF_FontFaceStyleName( recv );
if ( sn == NULL )
return String_as_nullable( NativeString_to_s( sn ) );
`}
- # Return the estimated width of a String if used with the current font
- fun width_of( text: String ): Int is extern import NativeString::to_s `{
+ # Return the estimated width of a String if used with the current font
+ fun width_of( text: String ): Int is extern import NativeString.to_s `{
char *ctext = String_to_cstring( text );
int w;
if ( TTF_SizeText( recv, ctext, &w, NULL ) )
redef fun read_param(it)
do
super
- if it.is_ok and it.item.first != '-' then
+ if it.is_ok and it.item.chars.first != '-' then
value = convert(it.item)
it.next
else
if str.last_index_of('-') == 0 and str.length > 2 then
var next_called = false
for i in [1..str.length] do
- var short_opt = "-" + str[i].to_s
+ var short_opt = "-" + str.chars[i].to_s
if _optmap.has_key(short_opt) then
var option = _optmap[short_opt]
if option isa OptionParameter then
# Check signals for safe operation
# will callback receiver of raised signals
# can callback any instance of SignalHandler, not just this one
- protected fun check_signals: Bool is extern import SignalHandler::receive_signal `{
+ protected fun check_signals: Bool is extern import SignalHandler.receive_signal `{
int sig;
int raised_something = 0;
fun descriptor: Int `{ return *recv; `}
fun errno: Int `{ return errno; `}
- fun gethostbyname(n: String): FFSocketHostent import String::to_cstring `{ return gethostbyname(String_to_cstring(n)); `}
+ fun gethostbyname(n: String): FFSocketHostent import String.to_cstring `{ return gethostbyname(String_to_cstring(n)); `}
fun connect(addrIn: FFSocketAddrIn): Int `{ return connect( *recv, (S_ADDR*)addrIn, sizeof(*addrIn) ); `}
- fun write(buffer: String): Int import String::to_cstring, String::length `{ return write(*recv, (char*)String_to_cstring(buffer), String_length(buffer)); `}
+ fun write(buffer: String): Int import String.to_cstring, String.length `{ return write(*recv, (char*)String_to_cstring(buffer), String_length(buffer)); `}
fun read: String `{
char *c = (char*)malloc(1024);
new done `{ return SQLITE_DONE; `} # 101 /* sqlite3_step() has finished executing */
fun is_done: Bool `{ return recv == SQLITE_DONE; `}
- redef fun to_s: String import NativeString::to_s `{
+ redef fun to_s: String import NativeString.to_s `{
#if SQLITE_VERSION_NUMBER >= 3007015
char *err = (char *)sqlite3_errstr(recv);
#else
return sqlite3_step(recv);
`}
- fun column_name(i: Int) : String import NativeString::to_s `{
+ fun column_name(i: Int) : String import NativeString.to_s `{
const char * name = (sqlite3_column_name(recv, i));
if(name == NULL){
name = "";
return sqlite3_column_int(recv, i);
`}
- fun column_text(i: Int) : String import NativeString::to_s `{
+ fun column_text(i: Int) : String import NativeString.to_s `{
char * ret = (char *) sqlite3_column_text(recv, i);
if( ret == NULL ){
ret = "";
end
extern class Sqlite3 `{sqlite3 *`}
- new open(filename: String) import String::to_cstring `{
+ new open(filename: String) import String.to_cstring `{
sqlite3 *self;
sqlite3_open(String_to_cstring(filename), &self);
return self;
fun close `{ sqlite3_close(recv); `}
- fun exec(sql : String): Sqlite3Code import String::to_cstring `{
+ fun exec(sql : String): Sqlite3Code import String.to_cstring `{
return sqlite3_exec(recv, String_to_cstring(sql), 0, 0, 0);
`}
- fun prepare(sql: String): nullable Statement import String::to_cstring, Statement as nullable `{
+ fun prepare(sql: String): nullable Statement import String.to_cstring, Statement as nullable `{
sqlite3_stmt *stmt;
int res = sqlite3_prepare_v2(recv, String_to_cstring(sql), -1, &stmt, 0);
if (res == SQLITE_OK)
import string_search
import time
+in "C Header" `{
+ #include <dirent.h>
+ #include <string.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <unistd.h>
+`}
+
redef class Object
# Simple I/O
fun dirname: String
do
var l = _length - 1 # Index of the last char
- if l > 0 and self[l] == '/' then l -= 1 # remove trailing `/`
+ if l > 0 and self.chars[l] == '/' then l -= 1 # remove trailing `/`
var pos = last_index_of_from('/', l)
if pos > 0 then
return substring(0, pos)
do
if path.is_empty then return self
if self.is_empty then return path
- if path[0] == '/' then return path
+ if path.chars[0] == '/' then return path
return "{self}/{path}"
end
end
# returns files contained within the directory represented by self
- fun files : Set[ String ] is extern import HashSet, HashSet::add, NativeString::to_s, String::to_cstring, HashSet[String] as( Set[String] ), String as( Object )
+ fun files : Set[ String ] is extern import HashSet[String], HashSet[String].add, NativeString.to_s, String.to_cstring, HashSet[String].as(Set[String]) `{
+ char *dir_path;
+ DIR *dir;
+
+ dir_path = String_to_cstring( recv );
+ if ((dir = opendir(dir_path)) == NULL)
+ {
+ perror( dir_path );
+ exit( 1 );
+ }
+ else
+ {
+ HashSet_of_String results;
+ String file_name;
+ struct dirent *de;
+
+ results = new_HashSet_of_String();
+
+ while ( ( de = readdir( dir ) ) != NULL )
+ if ( strcmp( de->d_name, ".." ) != 0 &&
+ strcmp( de->d_name, "." ) != 0 )
+ {
+ file_name = NativeString_to_s( strdup( de->d_name ) );
+ HashSet_of_String_add( results, file_name );
+ }
+
+ closedir( dir );
+ return HashSet_of_String_as_Set_of_String( results );
+ }
+ `}
end
redef class NativeString
#include "file_nit.h"
-#ifndef NONITCNI
-/*
-C implementation of file::String::files
-
-Imported methods signatures:
- HashSet new_HashSet( ) for hash_collection::HashSet::init
- void HashSet_add( HashSet recv, Object item ) for hash_collection::HashSet::(abstract_collection::SimpleCollection::add)
- String NativeString_to_s() for string::NativeString::to_s
- int HashSet_is_a_Set( HashSet value ) to check if a HashSet[String] is a Set[String]
- Set HashSet_as_Set( HashSet value ) to cast from HashSet[String] to Set[String]
-*/
-Set String_files___impl( String recv )
-{
- char *dir_path;
- DIR *dir;
-
- dir_path = String_to_cstring( recv );
- if ((dir = opendir(dir_path)) == NULL)
- {
- perror( dir_path );
- exit( 1 );
- }
- else
- {
- HashSet results;
- String file_name;
- struct dirent *de;
-
- results = new_HashSet();
-
- while ( ( de = readdir( dir ) ) != NULL )
- if ( strcmp( de->d_name, ".." ) != 0 &&
- strcmp( de->d_name, "." ) != 0 )
- {
- file_name = NativeString_to_s( strdup( de->d_name ) );
- HashSet_add( results, String_as_Object( file_name ) );
- }
-
- closedir( dir );
- return HashSet_as_Set( results );
- }
-}
-#endif
-
int string_NativeString_NativeString_file_exists_0(char *f){
FILE *hdl = fopen(f,"r");
if(hdl != NULL){
#include <stdio.h>
#include <sys/types.h>
-#ifndef NONITCNI
-#include <file._nitni.h>
-
-Set String_files___impl( String recv );
-#endif
-
extern int string_NativeString_NativeString_file_exists_0(char *f);
extern void *string_NativeString_NativeString_file_stat_0(char *f);
extern void *file_NativeFile_NativeFile_file_stat_0(FILE *f);
fun acos: Float is extern "kernel_Float_Float_acos_0"
fun asin: Float is extern "kernel_Float_Float_asin_0"
fun atan: Float is extern "kernel_Float_Float_atan_0"
+ fun abs: Float `{ return abs(recv); `}
fun pow(e: Float): Float is extern "kernel_Float_Float_pow_1"
fun log: Float is extern "kernel_Float_Float_log_0"
extern class Passwd `{struct passwd*`}
new from_uid(uid: Int) `{ return getpwuid(uid); `}
- new from_name(name: String) import String::to_cstring `{ return getpwnam( String_to_cstring(name) ); `}
+ new from_name(name: String) import String.to_cstring `{ return getpwnam( String_to_cstring(name) ); `}
- fun name: String import NativeString::to_s `{ return NativeString_to_s(recv->pw_name); `}
- fun passwd: String import NativeString::to_s `{ return NativeString_to_s(recv->pw_passwd); `}
+ fun name: String import NativeString.to_s `{ return NativeString_to_s(recv->pw_name); `}
+ fun passwd: String import NativeString.to_s `{ return NativeString_to_s(recv->pw_passwd); `}
fun uid: Int `{ return recv->pw_uid; `}
fun gid: Int `{ return recv->pw_gid; `}
- fun gecos: String import NativeString::to_s `{ return NativeString_to_s(recv->pw_gecos); `}
- fun dir: String import NativeString::to_s `{ return NativeString_to_s(recv->pw_dir); `}
- fun shell: String import NativeString::to_s `{ return NativeString_to_s(recv->pw_shell); `}
+ fun gecos: String import NativeString.to_s `{ return NativeString_to_s(recv->pw_gecos); `}
+ fun dir: String import NativeString.to_s `{ return NativeString_to_s(recv->pw_dir); `}
+ fun shell: String import NativeString.to_s `{ return NativeString_to_s(recv->pw_shell); `}
end
extern class Group `{struct group*`}
new from_gid(gid: Int) `{ return getgrgid(gid); `}
- new from_name(name: String) import String::to_cstring `{ return getgrnam( String_to_cstring(name) ); `}
+ new from_name(name: String) import String.to_cstring `{ return getgrnam( String_to_cstring(name) ); `}
- fun name: String import NativeString::to_s `{ return NativeString_to_s(recv->gr_name); `}
- fun passwd: String import NativeString::to_s `{ return NativeString_to_s(recv->gr_passwd); `}
+ fun name: String import NativeString.to_s `{ return NativeString_to_s(recv->gr_name); `}
+ fun passwd: String import NativeString.to_s `{ return NativeString_to_s(recv->gr_passwd); `}
fun gid: Int `{ return recv->gr_gid; `}
- fun mem: Array[String] import Array, Array::add, NativeString::to_s, String as (nullable Object) `{
+ fun mem: Array[String] import Array[String], Array[String].add, NativeString.to_s `{
char **mem;
int m;
- Array ret;
+ Array_of_String ret;
mem = recv->gr_mem;
- ret = new_Array();
+ ret = new_Array_of_String();
for (m = 0; mem[m] != NULL; m++)
- Array_add(ret, String_as_nullable_Object( NativeString_to_s(mem[m]) ));
+ Array_of_String_add(ret, NativeString_to_s(mem[m]));
return ret;
`}
module standard
import posix
-import ropes
import environ
import time
import string_search
import string
+in "C" `{
+ #include <unistd.h>
+ #include <poll.h>
+ #include <errno.h>
+ #include <string.h>
+`}
+
# Abstract stream class
interface IOS
# close the stream
if eof then return
else
var c = x.ascii
- s.push(c)
+ s.chars.push(c)
if c == '\n' then return
end
end
if _buffer_pos >= _buffer.length then
return -1
end
- var c = _buffer[_buffer_pos]
+ var c = _buffer.chars[_buffer_pos]
_buffer_pos += 1
return c.ascii
end
k = _buffer.length
end
while j < k and i > 0 do
- s.add(_buffer[j])
+ s.add(_buffer.chars[j])
j += 1
i -= 1
end
var j = _buffer_pos
var k = _buffer.length
while j < k do
- s.add(_buffer[j])
+ s.add(_buffer.chars[j])
j += 1
end
_buffer_pos = j
loop
# First phase: look for a '\n'
var i = _buffer_pos
- while i < _buffer.length and _buffer[i] != '\n' do i += 1
+ while i < _buffer.length and _buffer.chars[i] != '\n' do i += 1
# if there is something to append
if i > _buffer_pos then
# Copy from the buffer to the string
var j = _buffer_pos
while j < i do
- s.add(_buffer[j])
+ s.add(_buffer.chars[j])
j += 1
end
end
end
end
- private fun intern_poll( in_fds : Array[Int], out_fds : Array[Int] ) : nullable Int is extern import Array::length, Array::[], nullable Object as ( Int ), Int as nullable
+ private fun intern_poll(in_fds: Array[Int], out_fds: Array[Int]) : nullable Int is extern import Array[Int].length, Array[Int].[], Int.as(nullable Int) `{
+ int in_len, out_len, total_len;
+ struct pollfd *c_fds;
+ sigset_t sigmask;
+ int i;
+ int first_polled_fd = -1;
+ int result;
+
+ in_len = Array_of_Int_length( in_fds );
+ out_len = Array_of_Int_length( out_fds );
+ total_len = in_len + out_len;
+ c_fds = malloc( sizeof(struct pollfd) * total_len );
+
+ /* input streams */
+ for ( i=0; i<in_len; i ++ ) {
+ int fd;
+ fd = Array_of_Int__index( in_fds, i );
+
+ c_fds[i].fd = fd;
+ c_fds[i].events = POLLIN;
+ }
+
+ /* output streams */
+ for ( i=0; i<out_len; i ++ ) {
+ int fd;
+ fd = Array_of_Int__index( out_fds, i );
+
+ c_fds[i].fd = fd;
+ c_fds[i].events = POLLOUT;
+ }
+
+ /* poll all fds, unlimited timeout */
+ result = poll( c_fds, total_len, -1 );
+
+ if ( result > 0 ) {
+ /* analyse results */
+ for ( i=0; i<total_len; i++ )
+ if ( c_fds[i].revents & c_fds[i].events || /* awaited event */
+ c_fds[i].revents & POLLHUP ) /* closed */
+ {
+ first_polled_fd = c_fds[i].fd;
+ break;
+ }
+
+ return Int_as_nullable( first_polled_fd );
+ }
+ else if ( result < 0 )
+ fprintf( stderr, "Error in Stream:poll: %s\n", strerror( errno ) );
+
+ return null_Int();
+ `}
end
# Stream to a String. Mainly used for compatibility with OStream type and tests.
#include "stream_nit.h"
-#include <poll.h>
-#include <errno.h>
-
int stream_FDStream_FDStream_native_read_char_1(void *s, int fd) {
int result;
char buf;
ssize_t r = read(fd, &buf, 1);
- if (r == 0)
+ if (r == 0)
result = -1;
- else
+ else
result = buf;
return result;
}
-#ifndef NONITCNI
-
-/*
-C implementation of stream::Object::intern_poll
-
-Imported methods signatures:
- bigint Array_length( Array recv ) for array::AbstractArrayRead::(abstract_collection::Collection::length)
- nullable_Object Array__index( Array recv, bigint index ) for array::Array::(abstract_collection::SequenceRead::[])
- int nullable_Object_is_a_bigint( nullable_Object value ) to check if a nullable Object is a Int
- bigint nullable_Object_as_bigint( nullable_Object value ) to cast from nullable Object to Int
- int Int_is_null( nullable_Int value ) to check if a nullable Int is a Int
- bigint bigint_as_not_null( nullable_Int value ) to cast from nullable Int to Int
-*/
-nullable_Int Object_intern_poll___impl( Object recv, Array in_fds, Array out_fds ) {
- int in_len, out_len, total_len;
- struct pollfd *c_fds;
- sigset_t sigmask;
- int i;
- nullable_Object tmp_nit_obj;
- int first_polled_fd = -1;
- int result;
-
- in_len = Array_length( in_fds );
- out_len = Array_length( out_fds );
- total_len = in_len + out_len;
- c_fds = malloc( sizeof(struct pollfd) * total_len );
-
- /* input streams */
- for ( i=0; i<in_len; i ++ ) {
- int fd;
- tmp_nit_obj = Array__index( in_fds, i );
- fd = nullable_Object_as_Int( tmp_nit_obj );
-
- c_fds[i].fd = fd;
- c_fds[i].events = POLLIN;
- }
-
- /* output streams */
- for ( i=0; i<out_len; i ++ ) {
- int fd;
- tmp_nit_obj = Array__index( out_fds, i );
- fd = nullable_Object_as_Int( tmp_nit_obj );
-
- c_fds[i].fd = fd;
- c_fds[i].events = POLLOUT;
- }
-
- /* poll all fds, unlimited timeout */
- result = poll( c_fds, total_len, -1 );
-
- if ( result > 0 ) {
- /* analyse results */
- for ( i=0; i<total_len; i++ )
- if ( c_fds[i].revents & c_fds[i].events || /* awaited event */
- c_fds[i].revents & POLLHUP ) /* closed */
- {
- first_polled_fd = c_fds[i].fd;
- break;
- }
-
- return Int_as_nullable( first_polled_fd );
- }
- else if ( result < 0 )
- fprintf( stderr, "Error in Stream:poll: %s\n", strerror( errno ) );
-
- return null_Int();
-}
-#endif
int stream_FDStream_FDStream_native_read_char_1(void *s, int fd);
-#ifndef NONITCNI
-#include <stream._nitni.h>
-nullable_Int Object_intern_poll___impl( Object recv, Array in_fds, Array out_fds );
-#endif
-
#define stream_FDStream_FDStream_native_close_1(self, p0) (close(p0))
#define stream_FDStream_FDStream_native_read_3(s, i, b, l) read((i), ((b)), ((l)))
#define stream_FDStream_FDStream_native_write_3(s, i, b, l) write((i), ((b)), ((l)))
readable private var _items: NativeString
+ fun chars: StringCharView is abstract
+
# Access a character at `index` in the string.
#
# assert "abcd"[2] == 'c'
if from < count then
var r = new Buffer.with_capacity(count - from)
while from < count do
- r.push(_items[from])
+ r.chars.push(_items[from])
from += 1
end
return r.to_s
var i = 0
var neg = false
- for c in self
+ for c in self.chars
do
var v = c.to_i
if v > base then
fun is_numeric: Bool
do
var has_point_or_comma = false
- for i in self
+ for i in self.chars
do
if not i.is_numeric
then
fun to_upper: String
do
var s = new Buffer.with_capacity(length)
- for i in self do s.add(i.to_upper)
+ for i in self.chars do s.add(i.to_upper)
return s.to_s
end
fun to_lower : String
do
var s = new Buffer.with_capacity(length)
- for i in self do s.add(i.to_lower)
+ for i in self.chars do s.add(i.to_lower)
return s.to_s
end
# assert "\na\nb\tc\t".trim == "a\nb\tc"
fun trim: String
do
- if self._length == 0 then return self.to_s
+ if self.length == 0 then return self.to_s
# find position of the first non white space char (ascii < 32) from the start of the string
var start_pos = 0
- while self[start_pos].ascii <= 32 do
+ while self.chars[start_pos].ascii <= 32 do
start_pos += 1
- if start_pos == _length then return ""
+ if start_pos == length then return ""
end
# find position of the first non white space char from the end of the string
var end_pos = length - 1
- while self[end_pos].ascii <= 32 do
+ while self.chars[end_pos].ascii <= 32 do
end_pos -= 1
- if end_pos == start_pos then return self[start_pos].to_s
+ if end_pos == start_pos then return self.chars[start_pos].to_s
end
return self.substring(start_pos, end_pos - start_pos + 1)
end
do
var res = new Buffer
var underscore = false
- for c in self do
+ for c in self.chars do
if (c >= 'a' and c <= 'z') or (c >='A' and c <= 'Z') then
res.add(c)
underscore = false
fun escape_to_c: String
do
var b = new Buffer
- for c in self do
+ for c in self.chars do
if c == '\n' then
b.append("\\n")
else if c == '\0' then
end
end
+# Abstract class for the SequenceRead compatible
+# views on String and Buffer objects
+abstract class StringCharView
+ super SequenceRead[Char]
+
+ type SELFTYPE: AbstractString
+
+ private var target: SELFTYPE
+
+ private init(tgt: SELFTYPE)
+ do
+ target = tgt
+ end
+
+ redef fun is_empty do return target.is_empty
+
+ redef fun length do return target.length
+
+ redef fun has(c: Char): Bool
+ do
+ for i in self do
+ if i == c then return true
+ end
+ return false
+ end
+
+end
+
+# View on Buffer objects, extends Sequence
+# for mutation operations
+abstract class BufferCharView
+ super StringCharView
+ super Sequence[Char]
+
+ redef type SELFTYPE: Buffer
+
+end
+
# Immutable strings of characters.
class String
super Comparable
# Indes in _items of the last item of the string
readable var _index_to: Int
+ redef var chars: StringCharView = new FlatStringCharView(self)
+
################################################
# AbstractString specific methods #
################################################
var realFrom = _index_from + from
- if (realFrom + count) > _index_to then return new String.from_substring(realFrom, _index_to, _items)
+ if (realFrom + count) > _index_to then return new String.with_infos(_items, _index_to - realFrom + 1, realFrom, _index_to)
if count == 0 then return ""
- return new String.from_substring(realFrom, realFrom + count - 1, _items)
+ var to = realFrom + count - 1
+
+ return new String.with_infos(_items, to - realFrom + 1, realFrom, to)
end
redef fun substring_from(from: Int): String
# String Specific Methods #
##################################################
- # Creates a String object as a substring of another String
- #
- # From : index to start at
- #
- # To : Index to stop at (from + count -1)
- #
- private init from_substring(from: Int, to: Int, internalString: NativeString)
- do
- _items = internalString
- _index_from = from
- _index_to = to
- _length = to - from + 1
- end
-
private init with_infos(items: NativeString, len: Int, from: Int, to: Int)
do
self._items = items
end
end
+private class FlatStringIterator
+ super IndexedIterator[Char]
+
+ var target: String
+
+ var target_items: NativeString
+
+ var curr_pos: Int
+
+ init with_pos(tgt: String, pos: Int)
+ do
+ target = tgt
+ target_items = tgt.items
+ curr_pos = pos + target.index_from
+ end
+
+ redef fun is_ok do return curr_pos <= target.index_to
+
+ redef fun item do return target_items[curr_pos]
+
+ redef fun next do curr_pos += 1
+
+ redef fun index do return curr_pos - target.index_from
+
+end
+
+private class FlatStringCharView
+ super StringCharView
+
+ redef type SELFTYPE: String
+
+ redef fun [](index)
+ do
+ # Check that the index (+ index_from) is not larger than indexTo
+ # In other terms, if the index is valid
+ assert index >= 0
+ assert (index + target._index_from) <= target._index_to
+ return target._items[index + target._index_from]
+ end
+
+ redef fun iterator: IndexedIterator[Char] do return new FlatStringIterator.with_pos(target, 0)
+
+end
+
# Mutable strings of characters.
class Buffer
super AbstractString
redef type OTHER: String
+ redef var chars: BufferCharView = new FlatBufferCharView(self)
+
redef fun []=(index, item)
do
if index == length then
var l1 = length
var l2 = s.length
while i < l1 and i < l2 do
- var c1 = self[i].ascii
- var c2 = s[i].ascii
+ var c1 = self.chars[i].ascii
+ var c2 = s.chars[i].ascii
if c1 < c2 then
return true
else if c2 < c1 then
readable private var _capacity: Int
end
+private class FlatBufferCharView
+ super BufferCharView
+ super StringCapable
+
+ redef type SELFTYPE: Buffer
+
+ init(tgt: Buffer)
+ do
+ self.target = tgt
+ end
+
+ redef fun [](index) do return target._items[index]
+
+ redef fun []=(index, item)
+ do
+ assert index >= 0 and index <= length
+ if index == length then
+ add(item)
+ return
+ end
+ target._items[index] = item
+ end
+
+ redef fun push(c)
+ do
+ target.add(c)
+ end
+
+ redef fun add(c)
+ do
+ target.add(c)
+ end
+
+ fun enlarge(cap: Int)
+ do
+ target.enlarge(cap)
+ end
+
+ redef fun append(s)
+ do
+ var my_items = target.items
+ var s_length = s.length
+ if target.capacity < s.length then enlarge(s_length + target.length)
+ end
+
+ redef fun iterator: IndexedIterator[Char] do return new FlatBufferIterator.with_pos(target, 0)
+
+end
+
+private class FlatBufferIterator
+ super IndexedIterator[Char]
+
+ var target: Buffer
+
+ var target_items: NativeString
+
+ var curr_pos: Int
+
+ init with_pos(tgt: Buffer, pos: Int)
+ do
+ target = tgt
+ target_items = tgt.items
+ curr_pos = pos
+ end
+
+ redef fun index do return curr_pos
+
+ redef fun is_ok do return curr_pos < target.length
+
+ redef fun item do return target_items[curr_pos]
+
+ redef fun next do curr_pos += 1
+
+end
+
###############################################################################
# Refinement #
###############################################################################
# Sign
if self < 0 then
n = - self
- s[0] = '-'
+ s.chars[0] = '-'
else if self == 0 then
- s[0] = '0'
+ s.chars[0] = '0'
return
else
n = self
# Fill digits
var pos = digit_count(base) - 1
while pos >= 0 and n > 0 do
- s[pos] = (n % base).to_c
+ s.chars[pos] = (n % base).to_c
n = n / base # /
pos -= 1
end
var len = str.length
for i in [0..len-1] do
var j = len-1-i
- var c = str[j]
+ var c = str.chars[j]
if c == '0' then
continue
else if c == '.' then
end
end
- fun to_precision_native(nb: Int): String import NativeString::to_s `{
+ fun to_precision_native(nb: Int): String import NativeString.to_s `{
int size;
char *str;
redef fun to_s
do
var s = new Buffer.with_capacity(1)
- s[0] = self
+ s.chars[0] = self
return s.to_s
end
var j = from
while j < n - m + 1 do
var i = m - 1 # Cursor in the pattern
- while i >= 0 and _motif[i] == s[i + j] do i -= 1
+ while i >= 0 and _motif.chars[i] == s.chars[i + j] do i -= 1
if i < 0 then
return j
else
var gs = _gs[i] # Good shift
- var bc = bc(s[i+j]) - m + 1 + i # Bad char
+ var bc = bc(s.chars[i+j]) - m + 1 + i # Bad char
# Both are true, do move to the best
if gs > bc then
j += gs
var m = _length
var i = 0
while i < m - 1 do
- _bc_table[x[i]] = m - i - 1
+ _bc_table[x.chars[i]] = m - i - 1
i += 1
end
end
else
if i < g then g = i
f = i
- while g >= 0 and x[g] == x[g + m - 1 - f] do g -= 1
+ while g >= 0 and x.chars[g] == x.chars[g + m - 1 - f] do g -= 1
suff[i] = f - g
end
i -= 1
do
var stop = s.length
while from < stop do
- if s[from] == self then return from
+ if s.chars[from] == self then return from
from += 1
end
return -1
var stop = s.length - length + 1
while from < stop do
var i = length - 1
- while i >= 0 and self[i] == s[i + from] do i -= 1
+ while i >= 0 and self.chars[i] == s.chars[i + from] do i -= 1
# Test if we found
if i < 0 then return from
# Not found so try next one
fun html_escape: String
do
var ret = self
- if ret.has('&') then ret = ret.replace('&', "&")
- if ret.has('<') then ret = ret.replace('<', "<")
- if ret.has('>') then ret = ret.replace('>', ">")
- if ret.has('"') then ret = ret.replace('"', """)
+ if ret.chars.has('&') then ret = ret.replace('&', "&")
+ if ret.chars.has('<') then ret = ret.replace('<', "<")
+ if ret.chars.has('>') then ret = ret.replace('>', ">")
+ if ret.chars.has('"') then ret = ret.replace('"', """)
return ret
end
end
fun update `{ time(&recv); `}
- fun ctime: String import NativeString::to_s_with_copy `{
+ fun ctime: String import NativeString.to_s_with_copy `{
return NativeString_to_s_with_copy( ctime(&recv) );
`}
fun yday: Int `{ return recv->tm_yday; `}
fun is_dst: Bool `{ return recv->tm_isdst; `}
- fun asctime: String import NativeString::to_s_with_copy `{
+ fun asctime: String import NativeString.to_s_with_copy `{
return NativeString_to_s_with_copy( asctime(recv) );
`}
- fun strftime(format: String): String import String::to_cstring, NativeString::to_s `{
+ fun strftime(format: String): String import String.to_cstring, NativeString.to_s `{
char* buf, *c_format;
size_t res;
import typing
import auto_super_init
import frontend
+import common_ffi
# Add compiling options
redef class ToolContext
cc_paths.append(path_env.split_with(':'))
end
+ var compile_dir = toolcontext.opt_compile_dir.value
+ if compile_dir == null then compile_dir = ".nit_compile"
+ self.compile_dir = compile_dir
end
+ # The compilation directory
+ var compile_dir: String
+
protected fun write_and_make(compiler: AbstractCompiler)
do
var mainmodule = compiler.mainmodule
var time0 = get_time
self.toolcontext.info("*** WRITING C ***", 1)
- var compile_dir = toolcontext.opt_compile_dir.value
- if compile_dir == null then compile_dir = ".nit_compile"
-
compile_dir.mkdir
if self.toolcontext.opt_stacktrace.value then compiler.build_c_to_nit_bindings
self.toolcontext.info("Total C source files to compile: {cfiles.length}", 2)
+ # FFI
+ for m in mainmodule.in_importation.greaters do if mmodule2nmodule.keys.has(m) then
+ var amodule = mmodule2nmodule[m]
+ if m.uses_ffi or amodule.uses_legacy_ni then
+ compiler.finalize_ffi_for_module(amodule)
+ end
+ end
+
# Generate the Makefile
var makename = "{mainmodule.name}.mk"
p = orig_dir.join_path(p).simplify_path
cc_includes += " -I \"" + p + "\""
end
- if toolcontext.opt_no_stacktrace.value then
- makefile.write("CC = ccache cc\nCFLAGS = -g -O2\nCINCL = {cc_includes}\nLDFLAGS ?= \nLDLIBS ?= -lm -lgc\n\n")
- else
- makefile.write("CC = ccache cc\nCFLAGS = -g -O2\nCINCL = {cc_includes}\nLDFLAGS ?= \nLDLIBS ?= -lunwind -lm -lgc\n\n")
+
+ var linker_options = new HashSet[String]
+ for m in mainmodule.in_importation.greaters do if mmodule2nmodule.keys.has(m) then
+ var amod = mmodule2nmodule[m]
+ linker_options.add(amod.c_linker_options)
end
+
+ if not toolcontext.opt_no_stacktrace.value then
+ linker_options.add("-lunwind")
+ end
+
+ makefile.write("CC = ccache cc\nCFLAGS = -g -O2\nCINCL = {cc_includes}\nLDFLAGS ?= \nLDLIBS ?= -lm -lgc {linker_options.join(" ")}\n\n")
makefile.write("all: {outpath}\n\n")
var ofiles = new Array[String]
# Compile each required extern body into a specific .o
for f in compiler.extern_bodies do
- var basename = f.filename.basename(".c")
- var o = "{basename}.extern.o"
- var ff = orig_dir.join_path(f.filename).simplify_path
- makefile.write("{o}: {ff}\n\t$(CC) $(CFLAGS) -D NONITCNI {f.cflags} -c -o {o} {ff}\n\n")
- ofiles.add(o)
+ if f isa ExternCFile then
+ var basename = f.filename.basename(".c")
+ var o = "{basename}.extern.o"
+ var ff = orig_dir.join_path(f.filename).simplify_path
+ makefile.write("{o}: {ff}\n\t$(CC) $(CFLAGS) -D NONITCNI {f.cflags} -c -o {o} {ff}\n\n")
+ ofiles.add(o)
+ end
end
# Link edition
# Binds the generated C function names to Nit function names
fun build_c_to_nit_bindings
do
- var compile_dir = modelbuilder.toolcontext.opt_compile_dir.value
- if compile_dir == null then compile_dir = ".nit_compile"
+ var compile_dir = modelbuilder.compile_dir
var stream = new OFStream.open("{compile_dir}/C_fun_names")
stream.write("%\{\n#include \"c_functions_hash.h\"\n%\}\n")
self.header.add_decl("#include <gc_chooser.h>")
compile_header_structs
+ compile_nitni_structs
# Signal handler function prototype
self.header.add_decl("void show_backtrace(int);")
- # Global variable used by the legacy native interface
+ # Global variable used by intern methods
self.header.add_decl("extern int glob_argc;")
self.header.add_decl("extern char **glob_argv;")
self.header.add_decl("extern val *glob_sys;")
end
- # Declaration of structures the live Nit types
+ # Declaration of structures for live Nit types
protected fun compile_header_structs is abstract
+ # Declaration of structures for nitni undelying the FFI
+ protected fun compile_nitni_structs is abstract
+
# Generate the main C function.
# This function:
# * allocate the Sys object if it exists
v.add("\}")
end
- # List of additional .c files required to compile (native interface)
- var extern_bodies = new Array[ExternCFile]
+ # List of additional files required to compile (FFI)
+ var extern_bodies = new Array[ExternFile]
# This is used to avoid adding an extern file more than once
private var seen_extern = new ArraySet[String]
if b == 0 then return "n/a"
return ((a*10000/b).to_f / 100.0).to_precision(2)
end
+
+ fun finalize_ffi_for_module(nmodule: AModule)
+ do
+ var visitor = new_visitor
+ nmodule.finalize_ffi(visitor, modelbuilder)
+ nmodule.finalize_nitni(visitor)
+ end
+
+ # Does this compiler support the FFI?
+ fun supports_ffi: Bool do return false
end
# A file unit (may be more than one file if
var returnlabel: nullable String writable = null
end
-# An extern C file to compile
-class ExternCFile
- # The filename of the file
- var filename: String
- # Additionnal specific CC compiler -c flags
- var cflags: String
-end
-
redef class MType
# Return the C type associated to a given Nit static type
fun ctype: String do return "val*"
end
private var properties_cache: Map[MClass, Set[MProperty]] = new HashMap[MClass, Set[MProperty]]
end
+
+redef class AModule
+ # Does this module use the legacy native interface?
+ fun uses_legacy_ni: Bool is abstract
+
+ # Write FFI results to file
+ fun finalize_ffi(v: AbstractCompilerVisitor, modelbuilder: ModelBuilder) is abstract
+
+ # Write nitni results to file
+ fun finalize_nitni(v: AbstractCompilerVisitor) is abstract
+end
var body_impl : Writer = new Writer
# files to compile TODO check is appropriate
- #var files = new Array[String]
+ var files = new Array[String]
fun add_local_function( efc : CFunction )
do
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2012-2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Support for nesting C code within a Nit program using its FFI
+module c
+
+import ffi_base
+
+redef class FFILanguageAssignationPhase
+ var c_language: FFILanguage = new CLanguage(self)
+end
+
+class CLanguage
+ super FFILanguage
+
+ redef fun identify_language(n) do return n.is_c
+
+ redef fun compile_module_block(block, ecc, nmodule)
+ do
+ if block.is_c_header then
+ ecc.header_custom.add( block.location.as_line_pragma )
+ ecc.header_custom.add( block.code )
+ else if block.is_c_body then
+ ecc.body_custom.add( block.location.as_line_pragma )
+ ecc.body_impl.add( block.code )
+ end
+ end
+
+ redef fun compile_extern_method(block, m, ecc, nmodule)
+ do
+ var fc = new ExternCFunction(m, nmodule.mmodule.as(not null))
+ fc.decls.add( block.location.as_line_pragma )
+ fc.exprs.add( block.code )
+ ecc.add_exported_function( fc )
+ end
+
+ redef fun compile_extern_class(block, m, ecc, nmodule) do end
+
+ redef fun get_ftype(block, m) do return new ForeignCType(block.code)
+
+ redef fun compile_callback(callback, nmodule, mmodule, ecc)
+ do
+ callback.compile_callback_to_c(mmodule, ecc)
+ end
+end
+
+redef class AExternCodeBlock
+ fun is_c: Bool do return language_name == null or
+ language_name_lowered == "c" or language_name_lowered.has_prefix( "c " )
+
+ fun is_c_body: Bool do return language_name == null or
+ language_name_lowered == "c" or language_name_lowered == "c body"
+
+ fun is_c_header: Bool do return language_name_lowered == "c header"
+end
+
+redef class Location
+ fun as_line_pragma: String do return "#line {line_start} \"{file.filename}\"\n"
+end
+
+redef class AModule
+ var c_compiler_options writable = ""
+ var c_linker_options writable = ""
+end
+
+# An extern C file to compile
+class ExternCFile
+ super ExternFile
+
+ init (filename, cflags: String)
+ do
+ super filename
+
+ self.cflags = cflags
+ end
+
+ # Additionnal specific CC compiler -c flags
+ var cflags: String
+
+ redef fun hash do return filename.hash
+ redef fun ==(o) do return o isa ExternCFile and filename == o.filename
+end
+
+class ForeignCType
+ super ForeignType
+
+ redef var ctype: String
+
+ init(ctype: String)
+ do
+ self.ctype = ctype
+ end
+end
+
+redef class NitniCallback
+ fun compile_callback_to_c(nmodule: MModule, ffi_ccu: CCompilationUnit) do end
+end
+
+redef class Object
+ # Context when calling user C code from generated code
+ fun to_c_call_context: ToCCallContext do return once new ToCCallContext
+
+ # Context when calling generated code from user C code
+ fun from_c_call_context: FromCCallContext do return once new FromCCallContext
+end
+
+redef class MExplicitCall
+ redef fun compile_callback_to_c(mmodule, ffi_ccu)
+ do
+ var mproperty = mproperty.as(MMethod)
+
+ var full_cname = mproperty.build_cname(recv_mtype, mmodule, null, long_signature)
+ var friendly_cname = mproperty.build_cname(recv_mtype, mmodule, null, short_signature)
+ ffi_ccu.body_decl.add("#define {friendly_cname} {full_cname}\n")
+ end
+end
+
+# Context when calling user C code from generated code
+class ToCCallContext
+ super CallContext
+
+ private init do end
+
+ redef fun name_mtype(mtype)
+ do
+ if mtype isa MClassType and mtype.mclass.kind == extern_kind then return "void *"
+ return mtype.cname
+ end
+end
+
+# Context when calling generated code from user C code
+class FromCCallContext
+ super CallContext
+
+ private init do end
+
+ redef fun name_mtype(mtype) do return mtype.cname
+end
+
+class ExternCFunction
+ super CFunction
+
+ var method: AExternPropdef
+
+ init (method: AExternPropdef, mmodule: MModule)
+ do
+ self.method = method
+
+ var recv_mtype = method.mpropdef.mclassdef.bound_mtype
+ var csignature = method.mpropdef.mproperty.build_csignature(recv_mtype, mmodule, "___impl", long_signature, from_c_call_context)
+
+ super( csignature )
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2013 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# FFI concers common between the compilers and the interpreter.
+# Offers services to compile modules using foreign code. Mainly allows
+# to wrap foreign code in Nit methods.
+module common_ffi
+
+import parser
+import modelbuilder
+
+import nitni
+
+import ffi_base
+import extern_classes
+import header_dependency
+import c
+
+redef class MModule
+ # Does this module uses the FFI?
+ var uses_ffi: Bool = false
+end
+
+redef class AModule
+ # C compilation unit for the FFI files
+ private var ffi_ccu: nullable CCompilationUnit = null
+
+ # Foreign language used in this AModule
+ private var present_languages = new HashSet[FFILanguage]
+
+ # Callbacks used locally
+ var ffi_callbacks = new HashMap[FFILanguage, Set[NitniCallback]]
+
+ # Ensures all of the general foreign code of the module has been analyzed.
+ # Manages header blocks, extern class types and foreign dependancies between modules
+ fun ensure_compile_ffi_wrapper
+ do
+ if ffi_ccu != null then return
+
+ # ready extern code compiler
+ var ffi_ccu = new CCompilationUnit
+ self.ffi_ccu = ffi_ccu
+
+ # generate code
+ for block in n_extern_code_blocks do
+ var language = block.language
+ assert language != null
+ present_languages.add(language)
+ language.compile_module_block(block, ffi_ccu, self)
+ end
+
+ ffi_ccu.header_c_base.add( "#include \"{mmodule.name}._nitni.h\"\n" )
+
+ # include dependancies FFI
+ for mod in mmodule.header_dependencies do
+ if mod.uses_ffi then ffi_ccu.header_custom.add("#include \"{mod.name}._ffi.h\"\n")
+ end
+
+ for nclassdef in n_classdefs do
+ # Does it declares an extern type?
+ if nclassdef isa AStdClassdef and nclassdef.n_extern_code_block != null then
+ mmodule.uses_ffi = true
+ var language = nclassdef.n_extern_code_block.language
+ assert language != null
+ present_languages.add(language)
+ nclassdef.n_extern_code_block.language.compile_extern_class(
+ nclassdef.n_extern_code_block.as(not null), nclassdef, ffi_ccu, self)
+ end
+ end
+ end
+
+ # Complete the compilation of the FFI code
+ fun finalize_ffi_wrapper(compdir: String, mainmodule: MModule)
+ do
+ ensure_compile_ffi_wrapper
+
+ for language in present_languages do if ffi_callbacks.keys.has(language) then
+ for callback in ffi_callbacks[language] do
+ language.compile_callback(callback, self, mainmodule, ffi_ccu.as(not null))
+ end
+
+ language.compile_to_files(self, compdir)
+ end
+
+ ffi_ccu.write_as_impl(self, compdir)
+ for filename in ffi_ccu.files do ffi_files.add(new ExternCFile(filename, self.c_compiler_options))
+ end
+end
+
+redef class AExternPropdef
+ private var ffi_has_been_compiled = false
+
+ # Compile the necessary wrapper around this extern method or constructor
+ fun compile_ffi_method(amodule: AModule)
+ do
+ assert n_extern_code_block != null
+
+ if ffi_has_been_compiled then return
+ ffi_has_been_compiled = true
+
+ amodule.ensure_compile_ffi_wrapper
+
+ var language = n_extern_code_block.language
+ assert language != null
+ amodule.present_languages.add(language)
+ n_extern_code_block.language.compile_extern_method(
+ n_extern_code_block.as(not null), self, amodule.ffi_ccu.as(not null), amodule)
+ end
+end
+
+redef class VerifyNitniCallbacksPhase
+ redef fun process_npropdef(npropdef)
+ do
+ super
+
+ if not npropdef isa AExternPropdef then return
+
+ var code_block = npropdef.n_extern_code_block
+ if code_block == null then return
+
+ var lang = code_block.language
+ assert lang != null
+
+ # Associate callbacks used by an extern method to its foreign language
+ for callback in npropdef.foreign_callbacks.all do
+ var map = npropdef.parent.parent.as(AModule).ffi_callbacks
+ if not map.keys.has(lang) then map[lang] = new HashSet[NitniCallback]
+ map[lang].add(callback)
+ end
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2013 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Manages all extern classes and their associated foreign type.
+module extern_classes
+
+import ffi_base
+
+redef class ToolContext
+ var extern_classes_typing_phase_ast: Phase = new ExternClassesTypingPhaseAst(self, [ffi_language_assignation_phase])
+
+ var extern_classes_typing_phase_model: Phase = new ExternClassesTypingPhaseModel(self, [extern_classes_typing_phase_ast, modelize_class_phase])
+end
+
+# Assigns the `ftype` to class definitions, work on the AST only
+private class ExternClassesTypingPhaseAst
+ super Phase
+
+ redef fun process_nclassdef(nclassdef)
+ do
+ if not nclassdef isa AStdClassdef then return
+
+ var code_block = nclassdef.n_extern_code_block
+ if code_block == null then return
+
+ if nclassdef.n_kwredef != null then
+ # A redef cannot specifiy a different extern type
+ toolcontext.error(nclassdef.location, "Only the introduction of a class can specify an extern type.")
+ return
+ end
+
+ var ftype = code_block.language.get_ftype(code_block, nclassdef)
+ nclassdef.ftype_cache = ftype
+ nclassdef.ftype_computed = true
+ end
+end
+
+redef class AClassdef
+ private var ftype_cache: nullable ForeignType = null
+ private var ftype_computed = false
+
+ # Associated extern type when defined on this classdef
+ fun ftype: nullable ForeignType
+ do
+ return ftype_cache
+ end
+end
+
+private class ExternClassesTypingPhaseModel
+ super Phase
+
+ redef fun process_nclassdef(nclassdef)
+ do
+ if not nclassdef isa AStdClassdef then return
+
+ var mclassdef = nclassdef.mclassdef
+ var mclass = nclassdef.mclass
+
+ # We only need to do this once per class
+ if mclass.intro != mclassdef then return
+
+ if mclass.kind != extern_kind then return
+
+ mclass.compute_ftype(self)
+ end
+end
+
+redef class MClass
+ private var ftype_cache: nullable ForeignType = null
+ private var ftype_computed = false
+
+ # Extern type associated to this class according to specialisation
+ fun ftype: nullable ForeignType do return ftype_cache
+
+ redef fun ctype do return ftype_cache.ctype
+
+ # Type in C of the extern class
+ # If not defined in the intro of this class will look in super-classes
+ # FIXME this only supports type definition at intro, extend to superclasses by redef
+ private fun compute_ftype(v: ExternClassesTypingPhaseModel): nullable ForeignType
+ do
+ if ftype_computed then return ftype_cache
+ if kind != extern_kind then return null
+
+ # base case
+ if name == "Pointer" then
+ ftype_cache = new ForeignType
+ ftype_computed = true
+ return ftype_cache
+ end
+
+ var intro_nclassdef = v.toolcontext.modelbuilder.mclassdef2nclassdef[intro]
+ var ftype = intro_nclassdef.ftype
+ if ftype == null then
+ var ftype_b: nullable ForeignType = null # FIXME hack to circumvent bug where ftype is typed null
+
+ # look in super classes
+ for s in in_hierarchy(intro.mmodule).direct_greaters do
+ var super_ftype = s.compute_ftype(v)
+ if super_ftype != null then
+ if ftype_b == null then
+ ftype_b = super_ftype
+ continue
+ else
+ # detect conflict
+ if super_ftype != ftype_b then
+ v.toolcontext.error(null, "Extern type conflict in {self}")
+ return null
+ end
+ end
+ end
+ end
+
+ ftype = ftype_b
+ end
+
+ ftype_cache = ftype
+ ftype_computed = true
+ return ftype
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2012 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Tools and utilities for language targetted FFI implementations
+module ffi_base
+
+import c_tools
+import parser
+import modelbuilder
+import nitni
+
+redef class ToolContext
+ var ffi_language_assignation_phase: Phase = new FFILanguageAssignationPhase(self, null)
+end
+
+class FFILanguageAssignationPhase
+ super Phase
+
+ # All supported languages
+ var languages = new Array[FFILanguage]
+
+ redef fun process_nmodule(nmodule)
+ do
+ for block in nmodule.n_extern_code_blocks do
+ verify_foreign_code_on_node( block )
+ end
+ end
+
+ redef fun process_npropdef(npropdef)
+ do
+ if npropdef isa AExternPropdef then
+ var code_block = npropdef.n_extern_code_block
+ if code_block != null then
+ verify_foreign_code_on_node( code_block )
+ end
+ end
+ end
+
+ redef fun process_nclassdef(nclassdef)
+ do
+ if nclassdef isa AStdClassdef and nclassdef.n_extern_code_block != null then
+ verify_foreign_code_on_node( nclassdef.n_extern_code_block.as(not null) )
+ end
+ end
+
+ private fun verify_foreign_code_on_node(n: AExternCodeBlock)
+ do
+ var found = false
+ for v in languages do
+ var identified = v.identify_language(n)
+ if identified then
+ if found and identified then
+ toolcontext.error(n.location, "Two languages identified as possible handlers.")
+ end
+ n.language = v
+ found = true
+ end
+ end
+
+ if not found then toolcontext.error(n.location, "Unsupported language.")
+ end
+end
+
+redef class AModule
+ var ffi_files = new Array[ExternFile]
+end
+
+redef class AExternCodeBlock
+ fun language_name: nullable String do
+ if n_in_language == null then return null
+ return n_in_language.n_string.without_quotes
+ end
+ fun language_name_lowered: nullable String do
+ if language_name == null then return null
+ return language_name.to_lower
+ end
+
+ fun code: String do return n_extern_code_segment.without_guard
+
+ var language: nullable FFILanguage = null
+end
+
+# Visitor for a specific languages. Works kinda like a `Phase` and is executed
+# by a `Phase`.
+class FFILanguage
+ init(ffi_language_assignation_phase: FFILanguageAssignationPhase)
+ do
+ ffi_language_assignation_phase.languages.add(self)
+ end
+
+ # Is this `block` written in this language?
+ fun identify_language(block: AExternCodeBlock ): Bool is abstract
+
+ # Generate wrapper code for this module/header code block
+ fun compile_module_block(block: AExternCodeBlock, ecc: CCompilationUnit, nmodule: AModule) is abstract
+
+ # Generate wrapper code for this extern method
+ fun compile_extern_method(block: AExternCodeBlock, m: AExternPropdef,
+ ecc: CCompilationUnit, nmodule: AModule) is abstract
+
+ # Generate wrapper code for this extern class
+ fun compile_extern_class(block: AExternCodeBlock, m: AClassdef,
+ ecc: CCompilationUnit, nmodule: AModule) is abstract
+
+ # Get the foreign type of this extern class definition
+ fun get_ftype(block: AExternCodeBlock, m: AClassdef): ForeignType is abstract
+
+ # Generate the code to offer this callback if foreign code
+ fun compile_callback(callback: NitniCallback, nmodule: AModule,
+ mainmmodule: MModule, ecc: CCompilationUnit) is abstract
+
+ # Complete compilation of generated code
+ fun compile_to_files(amodule: AModule, directory: String) do end
+end
+
+redef class TString
+ # Returns the content of this node without both of the surrounding "
+ fun without_quotes: String
+ do
+ assert text.length >= 2
+ return text.substring(1, text.length-2)
+ end
+end
+
+redef class TExternCodeSegment
+ # Returns the content of this node without the surrounding `{ and `}
+ fun without_guard: String
+ do
+ assert text.length >= 4
+ return text.substring(2, text.length-4)
+ end
+end
+
+# An extern file to compile
+class ExternFile
+ # The filename of the file
+ var filename: String
+
+ fun makefile_rule_name: String is abstract
+ fun makefile_rule_content: String is abstract
+end
+
+redef class CCompilationUnit
+ fun write_as_impl( amodule: AModule, compdir: String )
+ do
+ var base_name = "{amodule.mmodule.name}._ffi"
+
+ var h_file = "{base_name}.h"
+ var guard = "{amodule.cname.to_s.to_upper}_NIT_H"
+ write_header_to_file( amodule, "{compdir}/{h_file}", new Array[String], guard)
+
+ var c_file = "{base_name}.c"
+ write_body_to_file( amodule, "{compdir}/{c_file}", ["<stdlib.h>", "<stdio.h>", "\"{h_file}\""] )
+
+ files.add( "{compdir}/{c_file}" )
+ end
+
+ fun write_header_to_file(amodule: AModule, file: String, includes: Array[String], guard: String)
+ do
+ var stream = new OFStream.open( file )
+
+ # header comments
+ var module_info = "/*\n\tExtern implementation of Nit module {amodule.mmodule.name}\n*/\n"
+
+ stream.write( module_info )
+
+ stream.write( "#ifndef {guard}\n" )
+ stream.write( "#define {guard}\n\n" )
+
+ for incl in includes do stream.write( "#include {incl}\n" )
+
+ compile_header_core( stream )
+
+ # header file guard close
+ stream.write( "#endif\n" )
+ stream.close
+ end
+
+ fun write_body_to_file(amodule: AModule, file: String, includes: Array[String])
+ do
+ var stream = new OFStream.open(file)
+
+ var module_info = "/*\n\tExtern implementation of Nit module {amodule.mmodule.name}\n*/\n"
+
+ stream.write( module_info )
+ for incl in includes do stream.write( "#include {incl}\n" )
+
+ compile_body_core( stream )
+
+ stream.close
+ end
+end
+
+class ForeignType
+ fun ctype: String do return "void*"
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2013 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Tracks which modules has public header code that must be imported
+# by user modules.
+module header_dependency
+
+import ffi_base
+import c
+
+redef class ToolContext
+ var header_dependancy_phase: Phase = new HeaderDependancyPhase(self, [ffi_language_assignation_phase, modelize_class_phase])
+end
+
+redef class AModule
+ private fun has_public_c_header: Bool do
+ for code_block in n_extern_code_blocks do if code_block.is_c_header then return true
+ return false
+ end
+end
+
+redef class MModule
+ private var header_dependencies_cache: nullable Array[MModule] = null
+ fun header_dependencies: Array[MModule]
+ do
+ var cache = header_dependencies_cache
+ assert cache != null
+ return cache
+ end
+
+ private fun compute_header_dependencies(v: HeaderDependancyPhase)
+ do
+ if header_dependencies_cache != null then return
+
+ var header_dependencies = new Array[MModule]
+
+ # gather from importation
+ for m in in_importation.direct_greaters do
+ m.compute_header_dependencies(v)
+
+ # does the super module has inherited dependancies?
+ var hd = m.header_dependencies
+ if not hd.is_empty then
+ header_dependencies.add_all(hd)
+ end
+
+ # does the super module itself has extern dependancies?
+ var amodule = v.toolcontext.modelbuilder.mmodule2nmodule[m]
+ if amodule.has_public_c_header then header_dependencies.add(m)
+ end
+
+ header_dependencies_cache = header_dependencies
+ end
+end
+
+private class HeaderDependancyPhase
+ super Phase
+
+ redef fun process_nmodule(nmodule)
+ do
+ var mmodule = nmodule.mmodule
+ mmodule.compute_header_dependencies(self)
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2013 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# FFI support for the compilers
+module compiler_ffi
+
+intrude import abstract_compiler
+intrude import common_ffi
+import nitni
+
+redef class AModule
+ private var foreign_callbacks = new ForeignCallbackSet
+ var nitni_ccu: nullable CCompilationUnit = null
+
+ redef var uses_legacy_ni: Bool = false
+
+ redef fun finalize_ffi(v: AbstractCompilerVisitor, modelbuilder: ModelBuilder)
+ do
+ finalize_ffi_wrapper(v.compiler.modelbuilder.compile_dir, v.compiler.mainmodule)
+ for file in ffi_files do v.compiler.extern_bodies.add(file)
+ end
+
+ fun ensure_compile_nitni_base(v: AbstractCompilerVisitor)
+ do
+ if nitni_ccu != null then return
+
+ nitni_ccu = new CCompilationUnit
+ end
+
+ redef fun finalize_nitni(v: AbstractCompilerVisitor)
+ do
+ ensure_compile_nitni_base(v)
+
+ nitni_ccu.header_c_types.add("#include \"{mmodule.name}._ffi.h\"\n")
+
+ nitni_ccu.write_as_nitni(self, v.compiler.modelbuilder.compile_dir)
+
+ for file in nitni_ccu.files do
+ v.compiler.extern_bodies.add(new ExternCFile(file, c_compiler_options))
+ end
+ end
+
+ var compiled_callbacks: Array[NitniCallback] = new Array[NitniCallback]
+
+ # Returns true if callbacks has yet to be generated and register it as being generated
+ fun check_callback_compilation(cb: NitniCallback): Bool
+ do
+ var compiled = compiled_callbacks.has(cb)
+ if not compiled then compiled_callbacks.add(cb)
+ return not compiled
+ end
+end
+
+redef class AExternPropdef
+ fun compile_ffi_support_to_c(v: AbstractCompilerVisitor)
+ do
+ var mmodule = mpropdef.mclassdef.mmodule
+ var amainmodule = v.compiler.modelbuilder.mmodule2nmodule[v.compiler.mainmodule]
+ var amodule = v.compiler.modelbuilder.mmodule2nmodule[mmodule]
+ var mclass_type = mpropdef.mclassdef.bound_mtype
+
+ # Declare as extern
+ var csignature = mpropdef.mproperty.build_csignature(mclass_type, mmodule, "___impl", long_signature, internal_call_context)
+ v.declare_once("{csignature};")
+
+ # FFI part
+ compile_ffi_method(amodule)
+
+ # nitni - Compile missing callbacks
+ amodule.ensure_compile_nitni_base(v)
+ var ccu = amodule.nitni_ccu.as(not null)
+
+ for mtype in foreign_callbacks.types do
+ if not mtype.is_cprimitive then
+ mtype.compile_extern_type(v, ccu)
+
+ # has callbacks already been compiled? (this may very well happen with global compilation)
+ if amodule.check_callback_compilation(mtype) then mtype.compile_extern_helper_functions(v, ccu)
+ end
+ end
+
+ # compile callbacks
+ for cb in foreign_callbacks.callbacks do if amainmodule.check_callback_compilation(cb) then
+ cb.compile_extern_callback(v, ccu)
+ end
+
+ for cb in foreign_callbacks.supers do if amainmodule.check_callback_compilation(cb) then
+ cb.compile_extern_callback(v, ccu)
+ end
+
+ for cb in foreign_callbacks.casts do if amainmodule.check_callback_compilation(cb) then
+ cb.compile_extern_callbacks(v, ccu)
+ end
+
+ # manage nitni callback set
+ amodule.foreign_callbacks.join(foreign_callbacks)
+ end
+end
+
+redef class AExternMethPropdef
+ redef fun compile_to_c(v, mpropdef, arguments)
+ do
+ var mmodule = mpropdef.mclassdef.mmodule
+ var amodule = v.compiler.modelbuilder.mmodule2nmodule[mmodule]
+
+ # if using the old native interface fallback on previous implementation
+ var nextern = self.n_extern
+ if nextern != null then
+ amodule.uses_legacy_ni = true
+ super
+ return
+ end
+
+ if not v.compiler.supports_ffi then
+ super
+ return
+ end
+
+ amodule.mmodule.uses_ffi = true
+
+ var mclass_type = mpropdef.mclassdef.bound_mtype
+
+ # Outgoing code in compiler
+ var externname = mpropdef.mproperty.build_cname(mpropdef.mclassdef.bound_mtype, mmodule, "___impl", long_signature)
+ var recv_var: nullable RuntimeVariable = null
+ var return_mtype = mpropdef.msignature.return_mtype
+ if return_mtype != null then
+ return_mtype = return_mtype.anchor_to(mmodule, mclass_type)
+ recv_var = v.new_var(return_mtype)
+ end
+
+ v.adapt_signature(mpropdef, arguments)
+
+ var arguments_for_c = new Array[String]
+ for a in [0..arguments.length[ do
+ var arg = arguments[a]
+ var param_mtype: MType
+ if a == 0 then
+ param_mtype = mpropdef.mclassdef.mclass.mclass_type
+ else param_mtype = mpropdef.msignature.mparameters[a-1].mtype
+
+ param_mtype = param_mtype.anchor_to(mmodule, mclass_type)
+
+ if param_mtype.is_cprimitive then
+ arguments_for_c.add(arg.name)
+ else
+ v.add("struct nitni_instance* var_for_c_{a};")
+ v.add("var_for_c_{a} = malloc(sizeof(struct nitni_instance));")
+ v.add("var_for_c_{a}->value = {arg.name};")
+ arguments_for_c.add("var_for_c_{a}")
+ end
+ end
+
+ if recv_var == null then
+ v.add("{externname}({arguments_for_c.join(", ")});")
+ else
+ assert return_mtype != null
+ if return_mtype.is_cprimitive then
+ v.add("{recv_var} = {externname}({arguments_for_c.join(", ")});")
+ else
+ v.add("struct nitni_instance* ret_var;")
+ v.add("ret_var = {externname}({arguments_for_c.join(", ")});")
+ v.add("{recv_var} = ret_var->value;")
+ end
+ v.ret(recv_var)
+ end
+
+ compile_ffi_support_to_c(v)
+ end
+end
+
+redef class AExternInitPropdef
+ redef fun compile_to_c(v, mpropdef, arguments)
+ do
+ var mmodule = mpropdef.mclassdef.mmodule
+ var amodule = v.compiler.modelbuilder.mmodule2nmodule[mmodule]
+
+ # if using the old native interface fallback on previous implementation
+ var nextern = self.n_extern
+ if nextern != null then
+ amodule.uses_legacy_ni = true
+ super
+ return
+ end
+
+ if not v.compiler.supports_ffi then
+ super
+ return
+ end
+
+ amodule.mmodule.uses_ffi = true
+
+ var mclass_type = mpropdef.mclassdef.bound_mtype
+
+ var externname = mpropdef.mproperty.build_cname(mpropdef.mclassdef.bound_mtype, mmodule, "___impl", long_signature)
+ var return_mtype = arguments.first.mtype
+ var recv_var = v.new_var(return_mtype)
+
+ v.adapt_signature(mpropdef, arguments)
+
+ arguments.shift
+
+ var arguments_for_c = new Array[String]
+ for a in [0..arguments.length[ do
+ var arg = arguments[a]
+ var param_mtype: MType
+ param_mtype = mpropdef.msignature.mparameters[a].mtype
+ param_mtype = param_mtype.anchor_to(mmodule, mclass_type)
+
+ if param_mtype.is_cprimitive then
+ arguments_for_c.add(arg.name)
+ else
+ v.add("struct nitni_instance* var_for_c_{a};")
+ v.add("var_for_c_{a} = malloc(sizeof(struct nitni_instance));")
+ v.add("var_for_c_{a}->value = {arg.name};")
+ arguments_for_c.add("var_for_c_{a}")
+ end
+ end
+
+ if return_mtype.is_cprimitive then
+ v.add("{recv_var} = {externname}({arguments_for_c.join(", ")});")
+ else
+ v.add("struct nitni_instance* ret_var;")
+ v.add("ret_var = {externname}({arguments_for_c.join(", ")});")
+ v.add("{recv_var} = ret_var->value;")
+ end
+ v.ret(recv_var)
+
+ compile_ffi_support_to_c(v)
+ end
+end
+
+redef class CCompilationUnit
+ fun write_as_nitni(amodule: AModule, compdir: String)
+ do
+ var base_name = "{amodule.mmodule.name}._nitni"
+
+ var h_file = "{base_name}.h"
+ write_header_to_file( amodule, "{compdir}/{h_file}", new Array[String],
+ "{amodule.cname.to_s.to_upper}_NITG_NITNI_H")
+
+ var c_file = "{base_name}.c"
+ write_body_to_file( amodule, "{compdir}/{c_file}", ["\"{h_file}\""] )
+
+ files.add( "{compdir}/{c_file}" )
+ end
+end
+
+redef class AbstractCompilerVisitor
+ # Create a `RuntimeVariable` for this C variable originating from C user code
+ private fun var_from_c(name: String, mtype: MType): RuntimeVariable
+ do
+ if mtype.is_cprimitive then
+ return new RuntimeVariable(name, mtype, mtype)
+ else
+ return new RuntimeVariable("{name}->value", mtype, mtype)
+ end
+ end
+
+ # Return a `RuntimeVarible` to C user code
+ private fun ret_to_c(src: RuntimeVariable, mtype: MType)
+ do
+ if mtype.is_cprimitive then
+ add("return {src};")
+ else
+ add("struct nitni_instance* ret_for_c;")
+ add("ret_for_c = malloc(sizeof(struct nitni_instance));")
+ add("ret_for_c->value = {src};")
+ add("return ret_for_c;")
+ end
+ end
+end
+
+redef class MType
+ fun compile_extern_type(v: AbstractCompilerVisitor, ccu: CCompilationUnit)
+ do
+ assert not is_cprimitive
+
+ # define friendly type
+ ccu.header_c_types.add("#ifndef NIT_TYPE_{cname}\n")
+ ccu.header_c_types.add("#define NIT_TYPE_{cname} 1\n")
+ ccu.header_c_types.add("typedef struct nitni_instance *{cname};\n")
+ ccu.header_c_types.add("#endif\n")
+ end
+
+ fun compile_extern_helper_functions(v: AbstractCompilerVisitor, ccu: CCompilationUnit)
+ do
+ # actually, we do not need to do anything when using the bohem garbage collector
+
+ # incr_ref
+ var nitni_visitor = v.compiler.new_visitor
+ ccu.header_decl.add("#define {mangled_cname}_incr_ref(from) while(0)\{\}\n")
+
+ # incr_ref
+ nitni_visitor = v.compiler.new_visitor
+ ccu.header_decl.add("#define {mangled_cname}_decr_ref(from) while(0)\{\}\n")
+ end
+end
+
+redef class MNullableType
+ redef fun compile_extern_helper_functions(v, ccu)
+ do
+ super
+
+ # In nitni files, declare internal function as extern
+ var full_friendly_csignature = "{cname} {v.compiler.mainmodule.name}___null_{mtype.mangled_cname}()"
+ ccu.header_decl.add("extern {full_friendly_csignature};\n")
+
+ # In nitni files, #define friendly as extern
+ var base_cname = "null_{mtype.mangled_cname}"
+ ccu.header_decl.add("#define {base_cname} {v.compiler.mainmodule.name}___{base_cname}\n")
+
+ # Internally, implement internal function
+ var nitni_visitor = v.compiler.new_visitor
+ nitni_visitor.frame = v.frame
+ var full_internal_csignature = "{cname_blind} {v.compiler.mainmodule.name}___null_{mtype.mangled_cname}()"
+ nitni_visitor.add("#ifndef NIT_NULL_null_{mtype.mangled_cname}")
+ nitni_visitor.add("#define NIT_NULL_null_{mtype.mangled_cname}")
+ nitni_visitor.add("{full_internal_csignature} \{")
+ nitni_visitor.add("struct nitni_instance* ret_for_c;")
+ nitni_visitor.add("ret_for_c = malloc(sizeof(struct nitni_instance));")
+ nitni_visitor.add("ret_for_c->value = NULL;")
+ nitni_visitor.add("return ret_for_c;")
+ nitni_visitor.add("\}")
+ nitni_visitor.add("#endif")
+ end
+end
+
+redef class MExplicitCall
+ fun compile_extern_callback(v: AbstractCompilerVisitor, ccu: CCompilationUnit)
+ do
+ var mproperty = mproperty
+ assert mproperty isa MMethod
+
+ # In nitni files, declare internal function as extern
+ var full_friendly_csignature = mproperty.build_csignature(recv_mtype, v.compiler.mainmodule, null, long_signature, internal_call_context)
+ ccu.header_decl.add("extern {full_friendly_csignature};\n")
+
+ # Internally, implement internal function
+ var nitni_visitor = v.compiler.new_visitor
+ nitni_visitor.frame = v.frame
+ var msignature = mproperty.intro.msignature
+ var csignature_blind = mproperty.build_csignature(recv_mtype, v.compiler.mainmodule, null, long_signature, internal_call_context)
+
+ nitni_visitor.add_decl("/* nitni callback for {mproperty.full_name} */")
+ nitni_visitor.add_decl("{csignature_blind} \{")
+
+ var vars = new Array[RuntimeVariable]
+ var mtype: MType = recv_mtype
+ var recv_var = null
+ if mproperty.is_init then
+ if recv_mtype.mclass.kind == extern_kind then
+ recv_var = nitni_visitor.new_var(mtype)
+ else
+ var recv_mtype = recv_mtype
+ recv_var = nitni_visitor.init_instance(recv_mtype)
+ nitni_visitor.add("{mtype.ctype} recv /* var self: {mtype} */;")
+ nitni_visitor.add("recv = {recv_var};")
+ end
+ else
+ mtype = mtype.anchor_to(v.compiler.mainmodule, recv_mtype)
+ recv_var = nitni_visitor.var_from_c("recv", mtype)
+ end
+
+ vars.add(recv_var)
+
+ for p in msignature.mparameters do
+ var arg_mtype = p.mtype.anchor_to(v.compiler.mainmodule, recv_mtype)
+ var arg = nitni_visitor.var_from_c(p.name, arg_mtype)
+ vars.add(arg)
+ end
+
+ var ret_var = nitni_visitor.send(mproperty, vars)
+
+ var return_mtype = msignature.return_mtype
+ if mproperty.is_init then
+ if recv_mtype.mclass.kind != extern_kind then ret_var = recv_var
+ return_mtype = recv_mtype
+ end
+ if return_mtype != null then
+ assert ret_var != null
+ return_mtype = return_mtype.anchor_to(v.compiler.mainmodule, recv_mtype)
+ nitni_visitor.ret_to_c(ret_var, return_mtype)
+ end
+ nitni_visitor.add("\}")
+ end
+end
+
+redef class MExplicitSuper
+ fun compile_extern_callback(v: AbstractCompilerVisitor, ccu: CCompilationUnit)
+ do
+ var mproperty = from.mproperty
+ assert mproperty isa MMethod
+ var mclass_type = from.mclassdef.mclass.mclass_type
+ var mmodule = from.mclassdef.mmodule
+
+ # In nitni files, declare internal function as extern
+ var internal_csignature = mproperty.build_csignature(mclass_type, v.compiler.mainmodule, null, long_signature, from_c_call_context)
+ ccu.header_decl.add("extern {internal_csignature};\n")
+
+ # In nitni files, #define friendly as extern
+ var friendly_cname = mproperty.build_cname(mclass_type, v.compiler.mainmodule, "___super", short_signature)
+ var internal_cname = mproperty.build_cname(mclass_type, v.compiler.mainmodule, "___super", long_signature)
+ ccu.header_decl.add("#define {friendly_cname} {internal_cname}\n")
+
+ # Internally, implement internal function
+ var nitni_visitor = v.compiler.new_visitor
+ nitni_visitor.frame = v.frame
+ var msignature = mproperty.intro.msignature
+
+ var csignature_blind = mproperty.build_csignature(mclass_type, v.compiler.mainmodule, "___super", long_signature, internal_call_context)
+
+ nitni_visitor.add_decl("/* nitni callback to super for {mproperty.full_name} */")
+ nitni_visitor.add_decl("{csignature_blind} \{")
+
+ var vars = new Array[RuntimeVariable]
+
+ var recv_var = nitni_visitor.var_from_c("recv", mclass_type)
+ vars.add(recv_var)
+
+ for p in msignature.mparameters do
+ var arg_mtype = v.anchor(p.mtype)
+ var arg = nitni_visitor.var_from_c(p.name, arg_mtype)
+ vars.add(arg)
+ end
+
+ var ret_var = nitni_visitor.supercall(from.as(MMethodDef), mclass_type, vars)
+
+ var return_mtype = msignature.return_mtype
+ if return_mtype != null then
+ assert ret_var != null
+ return_mtype = v.anchor(return_mtype)
+ nitni_visitor.ret_to_c(ret_var, return_mtype)
+ end
+ nitni_visitor.add("\}")
+ end
+end
+
+redef class MExplicitCast
+ fun compile_extern_callbacks(v: AbstractCompilerVisitor, ccu: CCompilationUnit)
+ do
+ var from = from
+ var to = to
+
+ #
+ ## check type
+ #
+
+ # In nitni files, declare internal function as extern
+ var full_friendly_csignature = "int {v.compiler.mainmodule.name }___{from.mangled_cname}_is_a_{to.mangled_cname}({from.cname_blind})"
+ ccu.header_decl.add("extern {full_friendly_csignature};\n")
+
+ # In nitni files, #define friendly as extern
+ ccu.header_decl.add("#define {check_cname} {v.compiler.mainmodule.name}___{check_cname}\n")
+
+ # Internally, implement internal function
+ var nitni_visitor = v.compiler.new_visitor
+ nitni_visitor.frame = v.frame
+
+ var full_internal_csignature = "int {v.compiler.mainmodule.name }___{from.mangled_cname}_is_a_{to.mangled_cname}({from.cname_blind} from)"
+ nitni_visitor.add_decl("/* nitni check for {from} to {to} */")
+ nitni_visitor.add_decl("{full_internal_csignature} \{")
+
+ var from_var = new RuntimeVariable("from->value", from, from)
+ var recv_var = nitni_visitor.type_test(from_var, to, "FFI isa")
+ nitni_visitor.add("return {recv_var};")
+
+ nitni_visitor.add("\}")
+
+ # special checks
+ if from == to.as_nullable then
+ # format A_is_null
+ ccu.header_decl.add("#define {from.mangled_cname}_is_null {from.mangled_cname}_is_a_{to.mangled_cname}\n")
+ end
+
+ #
+ ## cast
+ #
+
+ # In nitni files, declare internal function as extern
+ full_friendly_csignature = "{to.cname} {v.compiler.mainmodule.name }___{from.mangled_cname}_as_{to.mangled_cname}({from.cname_blind})"
+ ccu.header_decl.add("extern {full_friendly_csignature};\n")
+
+ # In nitni files, #define friendly as extern
+ ccu.header_decl.add("#define {cast_cname} {v.compiler.mainmodule.name}___{cast_cname}\n")
+
+ # Internally, implement internal function
+ nitni_visitor = v.compiler.new_visitor
+ nitni_visitor.frame = v.frame
+
+ full_internal_csignature = "{to.cname_blind} {v.compiler.mainmodule.name }___{from.mangled_cname}_as_{to.mangled_cname}({from.cname_blind} from)"
+ nitni_visitor.add_decl("/* nitni cast for {from} to {to} */")
+ nitni_visitor.add_decl("{full_internal_csignature} \{")
+
+ from_var = nitni_visitor.var_from_c("from", from)
+
+ ## test type
+ var check = nitni_visitor.type_test(from_var, to, "FFI cast")
+ nitni_visitor.add("if (!{check}) \{")
+ nitni_visitor.add_abort("FFI cast failed")
+ nitni_visitor.add("\}")
+
+ ## internal cast
+ recv_var = nitni_visitor.autobox(from_var, to)
+
+ nitni_visitor.ret_to_c(recv_var, to)
+
+ nitni_visitor.add("\}")
+
+ # special casts
+ if from.as_nullable == to then
+ # format A_as_nullable
+ ccu.header_decl.add("#define {from.mangled_cname}_as_nullable {from.mangled_cname}_as_{to.mangled_cname}\n")
+ end
+
+ if from == to.as_nullable then
+ # format A_as_nullable
+ ccu.header_decl.add("#define {to.mangled_cname}_as_not_nullable {from.mangled_cname}_as_{to.mangled_cname}\n")
+ end
+ end
+end
print "\nEnd of current instruction \n"
else if parts_of_command[1] == "stack" then
print self.stack_trace
- else if parts_of_command[1].has('[') and parts_of_command[1].has(']') then
+ else if parts_of_command[1].chars.has('[') and parts_of_command[1].chars.has(']') then
process_array_command(parts_of_command)
else
var instance = seek_variable(get_real_variable_name(parts_of_command[1]), frame)
var trigger_string_escape = false
var trigger_concat_in_string = false
- for i in instruction do
+ for i in instruction.chars do
if trigger_char_escape then
if i == '\'' then trigger_char_escape = false
else if trigger_string_escape then
if i.is_alphanumeric or i == '_' then
instruction_buffer.add(i)
else if i == '.' then
- if instruction_buffer.is_numeric or (instruction_buffer[0] >= 'A' and instruction_buffer[0] <= 'Z') then
+ if instruction_buffer.is_numeric or (instruction_buffer.chars[0] >= 'A' and instruction_buffer.chars[0] <= 'Z') then
instruction_buffer.clear
else
result_array.push(instruction_buffer.to_s)
trigger_concat_in_string = false
trigger_string_escape = true
else
- if instruction_buffer.length > 0 and not instruction_buffer.is_numeric and not (instruction_buffer[0] >= 'A' and instruction_buffer[0] <= 'Z') then result_array.push(instruction_buffer.to_s)
+ if instruction_buffer.length > 0 and not instruction_buffer.is_numeric and not (instruction_buffer.chars[0] >= 'A' and instruction_buffer.chars[0] <= 'Z') then result_array.push(instruction_buffer.to_s)
instruction_buffer.clear
end
end
end
- if instruction_buffer.length > 0 and not instruction_buffer.is_numeric and not (instruction_buffer[0] >= 'A' and instruction_buffer[0] <= 'Z') then result_array.push(instruction_buffer.to_s)
+ if instruction_buffer.length > 0 and not instruction_buffer.is_numeric and not (instruction_buffer.chars[0] >= 'A' and instruction_buffer.chars[0] <= 'Z') then result_array.push(instruction_buffer.to_s)
return result_array
end
var buf = new Buffer
var trigger_copy = false
- for i in function do
+ for i in function.chars do
if i == ')' then break
if trigger_copy then buf.add(i)
if i == '(' then trigger_copy = true
var last_was_opening_bracket = false
- for i in braces do
+ for i in braces.chars do
if i == '[' then
if last_was_opening_bracket then
return null
fun get_char(value: String): nullable Instance
do
if value.length >= 1 then
- return char_instance(value[0])
+ return char_instance(value.chars[0])
else
return null
end
--- /dev/null
+set -e
+set -x
+
+# Check c_src is up-to-date
+make -C ../c_src
+
+# Compile nitg
+time ../c_src/nitg nitg.nit
+
+# delete old c_src
+rm -rf ../c_src
+
+# Regenerate c_src
+./mkcsrc
+
+# Compile new c_src
+time make -C ../c_src
+
+# Remake all
+make
import abstract_compiler
import rapid_type_analysis
+import compiler_ffi
redef class ModelBuilder
# Entry point to performs a global compilation on the AST of a complete program.
v.add("res->value = value;")
v.add("return (val*)res;")
v.add("\}")
-
end
redef fun new_visitor do return new GlobalCompilerVisitor(self)
private var collect_types_cache: HashMap[MType, Array[MClassType]] = new HashMap[MType, Array[MClassType]]
+
+ redef fun compile_nitni_structs
+ do
+ self.header.add_decl("struct nitni_instance \{ val *value; \};")
+ end
+
+ redef fun supports_ffi do return true
end
# A visitor on the AST of property definition that generate the C code.
end
self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
return res
+ else if value.mtype.cname_blind == "void*" and mtype.cname_blind == "void*" then
+ return value
else
# Bad things will appen!
var res = self.new_var(mtype)
v.toolcontext.error(self.hot_location, "Invalid character literal {txt}")
return
end
- self.value = txt[1]
+ self.value = txt.chars[1]
end
end
do
var txt = self.n_string.text
var skip = 1
- if txt[0] == txt[1] and txt.length >= 6 then skip = 3
+ if txt.chars[0] == txt.chars[1] and txt.length >= 6 then skip = 3
self.value = txt.substring(skip, txt.length-(2*skip)).unescape_nit
end
end
var line_start = l.file.line_starts[i-1]
var line_end = line_start
var string = l.file.string
- while line_end+1 < string.length and string[line_end+1] != '\n' and string[line_end+1] != '\r' do
+ while line_end+1 < string.length and string.chars[line_end+1] != '\n' and string.chars[line_end+1] != '\r' do
line_end += 1
end
var lstart = string.substring(line_start, l.column_start - 1)
end
var indent = new Buffer
for j in [line_start..line_start+l.column_start-1[ do
- if string[j] == '\t' then
+ if string.chars[j] == '\t' then
indent.add '\t'
else
indent.add ' '
# Count the number of spaces
lastindent = indent
indent = 0
- while text.length > indent and text[indent] == ' ' do indent += 1
+ while text.length > indent and text.chars[indent] == ' ' do indent += 1
# Is codeblock? Then just collect them
if indent > 4 then
#!/bin/bash
cd ..
-out=c_src2
+out=c_src
rm -r "$out/" 2> /dev/null
set -e
set -x
end
# Second, filter the most specific ones
- var res = new Array[MPROPDEF]
- for pd1 in candidates do
- var cd1 = pd1.mclassdef
- var c1 = cd1.mclass
- var keep = true
- for pd2 in candidates do
- if pd2 == pd1 then continue # do not compare with self!
- var cd2 = pd2.mclassdef
- var c2 = cd2.mclass
- if c2.mclass_type == c1.mclass_type then
- if cd2.mmodule.in_importation <= cd1.mmodule then
- # cd2 refines cd1; therefore we skip pd1
- keep = false
- break
- end
- else if cd2.bound_mtype.is_subtype(mmodule, null, cd1.bound_mtype) then
- # cd2 < cd1; therefore we skip pd1
- keep = false
- break
- end
- end
- if keep then
- res.add(pd1)
- end
- end
- if res.is_empty then
- print "All lost! {candidates.join(", ")}"
- # FIXME: should be abort!
- end
- self.lookup_definitions_cache[mmodule, mtype] = res
- return res
+ return select_most_specific(mmodule, candidates)
end
private var lookup_definitions_cache: HashMap2[MModule, MType, Array[MPROPDEF]] = new HashMap2[MModule, MType, Array[MPROPDEF]]
# If you want the really most specific property, then look at `lookup_next_definition`
#
# FIXME: Move to `MPropDef`?
- fun lookup_super_definitions(mmodule: MModule, mtype: MType): Array[MPropDef]
+ fun lookup_super_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF]
do
assert not mtype.need_anchor
if mtype isa MNullableType then mtype = mtype.mtype
# First, select all candidates
- var candidates = new Array[MPropDef]
+ var candidates = new Array[MPROPDEF]
for mpropdef in self.mpropdefs do
# If the definition is not imported by the module, then skip
if not mmodule.in_importation <= mpropdef.mclassdef.mmodule then continue
if candidates.length <= 1 then return candidates
# Second, filter the most specific ones
- var res = new Array[MPropDef]
+ return select_most_specific(mmodule, candidates)
+ end
+
+ # Return an array containing olny the most specific property definitions
+ # This is an helper function for `lookup_definitions` and `lookup_super_definitions`
+ private fun select_most_specific(mmodule: MModule, candidates: Array[MPROPDEF]): Array[MPROPDEF]
+ do
+ var res = new Array[MPROPDEF]
for pd1 in candidates do
var cd1 = pd1.mclassdef
var c1 = cd1.mclass
var cd2 = pd2.mclassdef
var c2 = cd2.mclass
if c2.mclass_type == c1.mclass_type then
- if cd2.mmodule.in_importation <= cd1.mmodule then
+ if cd2.mmodule.in_importation < cd1.mmodule then
# cd2 refines cd1; therefore we skip pd1
keep = false
break
end
- else if cd2.bound_mtype.is_subtype(mmodule, null, cd1.bound_mtype) then
+ else if cd2.bound_mtype.is_subtype(mmodule, null, cd1.bound_mtype) and cd2.bound_mtype != cd1.bound_mtype then
# cd2 < cd1; therefore we skip pd1
keep = false
break
var inherit_init_from: nullable MClass = null
end
+redef class MClassDef
+ private var propdef_names = new HashSet[String]
+end
+
redef class AClassdef
var build_properties_is_done: Bool = false
# The list of super-constructor to call at the start of the free constructor
var mpropdef = new MMethodDef(mclassdef, mprop, self.location)
+ if mclassdef.propdef_names.has(mprop.name) then
+ var loc: nullable Location = null
+ for i in mclassdef.mpropdefs do
+ if i.mproperty.name == mprop.name then
+ loc = i.location
+ break
+ end
+ end
+ if loc == null then abort
+ modelbuilder.error(self, "Error: a property {mprop} is already defined in class {mclassdef.mclass} at {loc}")
+ end
+
+ mclassdef.propdef_names.add(mpropdef.mproperty.name)
+
self.mpropdef = mpropdef
modelbuilder.mpropdef2npropdef[mpropdef] = self
if mpropdef.is_intro then
for i in [0..mysignature.arity[ do
var myt = mysignature.mparameters[i].mtype
var prt = msignature.mparameters[i].mtype
- if not myt.is_subtype(mmodule, nclassdef.mclassdef.bound_mtype, prt) and
+ if not myt.is_subtype(mmodule, nclassdef.mclassdef.bound_mtype, prt) or
not prt.is_subtype(mmodule, nclassdef.mclassdef.bound_mtype, myt) then
- modelbuilder.error(nsig.n_params[i], "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
+ modelbuilder.error(nsig.n_params[i], "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt} as in {mpropdef.mproperty.intro}.")
end
end
end
# Inherit the return type
ret_type = precursor_ret_type
else if not ret_type.is_subtype(mmodule, nclassdef.mclassdef.bound_mtype, precursor_ret_type) then
- modelbuilder.error(nsig.n_type.as(not null), "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
+ modelbuilder.error(nsig.n_type.as(not null), "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type} as in {mpropdef.mproperty.intro}.")
end
end
end
if arg1 >= recvval.length or arg1 < 0 then
debug("Illegal access on {recvval} for element {arg1}/{recvval.length}")
end
- return v.char_instance(recvval[arg1])
+ return v.char_instance(recvval.chars[arg1])
else if pname == "[]=" then
var arg1 = args[1].to_i
if arg1 >= recvval.length or arg1 < 0 then
debug("Illegal access on {recvval} for element {arg1}/{recvval.length}")
end
- recvval[arg1] = args[2].val.as(Char)
+ recvval.chars[arg1] = args[2].val.as(Char)
return null
else if pname == "copy_to" then
# sig= copy_to(dest: NativeString, length: Int, from: Int, to: Int)
do
var loc_buf = new Buffer
if connection.ready_to_read(0) then buf.append(connection.read)
- for i in [buf_pos .. buf.length-1] do loc_buf.add(buf[i])
+ for i in [buf_pos .. buf.length-1] do loc_buf.add(buf.chars[i])
buf.clear
buf_pos = 0
return loc_buf.to_s
buf.append(connection.read)
end
buf_pos += 1
- return buf[buf_pos-1].ascii
+ return buf.chars[buf_pos-1].ascii
end
# Reads a line on the network if available
buf.append(connection.read)
end
buf_pos += 1
- if buf[buf_pos-1] == '\n' then break
- line_buf.add(buf[buf_pos-1])
+ if buf.chars[buf_pos-1] == '\n' then break
+ line_buf.add(buf.chars[buf_pos-1])
end
return line_buf.to_s
end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2013 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Native interface related services (used underneath the FFI)
+#
+# All nitni properties may not be visible to the user but they are
+# shared between engines
+module nitni
+
+import nitni_base
+import nitni_callbacks
+import nitni_utilities
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2012 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Native interface related services (used underneath the FFI)
+#
+# All nitni properties may not be visible to the user but they are
+# shared between engines
+module nitni_base
+
+import parser
+import modelbuilder # builder only for externcalls
+
+redef class MMethod
+ # Short name of this method in C (without the class name)
+ fun short_cname: String do
+ var nit_name = name
+
+ if nit_name == "+" then return "_plus"
+ if nit_name == "-" then return "_minus"
+ if nit_name == "*" then return "_star"
+ if nit_name == "/" then return "_slash"
+ if nit_name == "%" then return "_percent"
+ if nit_name == "[]" then return "_index"
+ if nit_name == "[]=" then return "_index_assign"
+ if nit_name == "==" then return "_equal"
+ if nit_name == "<" then return "_less"
+ if nit_name == ">" then return "_geater"
+ if nit_name == "<=" then return "_less_or_equal"
+ if nit_name == ">=" then return "_greater_or_equal"
+ if nit_name == "!=" then return "_not_equal"
+ if nit_name == "<<" then return "_left"
+ if nit_name == ">>" then return "_right"
+ if nit_name == "<=>" then return "_starship"
+
+ if nit_name.last == '=' then return "{nit_name.substring(0, nit_name.length-1)}__assign"
+ return nit_name
+ end
+end
+
+redef class AModule
+ # Mangled name of this module in C
+ fun cname: String do return mmodule.name
+end
+
+redef class MMethodDef
+ # Name of the function to callback this method from C,
+ # also used in other functions names used for this method.
+ fun cname: String do return "{mclassdef.mclass.name}_{mproperty.short_cname}"
+end
+
+redef class MType
+ # Representation of this type in pure C on the FFI extern side
+ # Object -> Object
+ # Pointer -> void*
+ fun cname: String is abstract
+
+ # Representation of this type in C for the internal of the system
+ # Hides extern types.
+ fun cname_blind: String is abstract
+
+ # Representation of this type in mangled C
+ # Object -> Object
+ # Pointer -> Pointer
+ fun mangled_cname: String is abstract
+
+ # Does this types has a primitive reprensentation
+ # type Object is_primitive? false
+ # type Pointer is_primitive? true
+ fun is_cprimitive: Bool is abstract
+end
+
+redef class MClassType
+ redef fun cname
+ do
+ var name = mclass.name
+ if name == "Bool" then return "int"
+ if name == "Char" then return "char"
+ if name == "Float" then return "double"
+ if name == "Int" then return "int"
+ if name == "NativeString" then return "char*"
+ if mclass.kind == extern_kind then
+ var ctype = mclass.ctype
+ assert ctype != null
+ return ctype
+ end
+ return mangled_cname
+ end
+
+ redef fun cname_blind do
+ var name = mclass.name
+ if name == "Bool" then return "int"
+ if name == "Char" then return "char"
+ if name == "Float" then return "double"
+ if name == "Int" then return "int"
+ if name == "NativeString" then return "char*"
+ if mclass.kind == extern_kind then return "void*"
+ return "struct nitni_instance *"
+ end
+
+ redef fun mangled_cname do return mclass.name
+
+ redef fun is_cprimitive do return mclass.kind == extern_kind or
+ (once ["Bool", "Char", "Float", "Int", "NativeString"]).has(mclass.name)
+end
+
+redef class MNullableType
+ redef fun cname do return mangled_cname
+ redef fun cname_blind do return "struct nitni_instance *"
+ redef fun mangled_cname do return "nullable_{mtype.mangled_cname}"
+ redef fun is_cprimitive do return false
+end
+
+redef class MVirtualType
+ redef fun mangled_cname: String do return to_s
+end
+
+redef class MGenericType
+ redef fun cname do return mangled_cname
+ redef fun mangled_cname
+ do
+ var base = super
+
+ var params = new Array[String]
+ for arg in arguments do params.add(arg.mangled_cname)
+
+ return "{base}_of_{params.join("_")}"
+ end
+end
+
+redef class MClass
+ fun ctype: nullable String
+ do
+ assert kind == extern_kind
+ return "void*"
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2012-2013 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# nitni services related to callbacks (used underneath the FFI)
+module nitni_callbacks
+
+import modelbuilder
+intrude import rapid_type_analysis
+
+import nitni_base
+
+redef class ToolContext
+ var verify_nitni_callback_phase: Phase = new VerifyNitniCallbacksPhase(self, [typing_phase])
+end
+
+# * checks for the validity of callbacks
+# * store the callbacks on each method
+class VerifyNitniCallbacksPhase
+ super Phase
+
+ redef fun process_npropdef(npropdef)
+ do
+ if not npropdef isa AExternPropdef then return
+
+ npropdef.verify_nitni_callbacks(toolcontext)
+ end
+end
+
+# Provides a better API but mainly the same content as AExternCalls
+class ForeignCallbackSet
+ # set of imported functions, cached to avoid repetitions
+ var callbacks: Set[ MExplicitCall ] = new HashSet[ MExplicitCall ]
+
+ # set of imported functions, cached to avoid repetitions
+ var supers: Set[ MExplicitSuper ] = new HashSet[ MExplicitSuper ]
+
+ # set of relevant types, cached to avoid repetitions
+ var types: Set[ MType ] = new HashSet[ MType ]
+
+ # set of imported casts and as, cached to avoid repetitions
+ var casts: Set[ MExplicitCast ] = new HashSet[ MExplicitCast ]
+
+ # Utility function, must be called only when all other maps are filled
+ private var all_cached: nullable Set[NitniCallback] = null
+ fun all: Set[NitniCallback]
+ do
+ var cached = all_cached
+ if cached != null then return cached
+
+ var set = new HashSet[NitniCallback]
+ set.add_all(callbacks)
+ set.add_all(supers)
+ set.add_all(types)
+ set.add_all(casts)
+
+ self.all_cached = set
+ return set
+ end
+
+ # Integrate content from the `other` set into this one
+ fun join(other: ForeignCallbackSet)
+ do
+ callbacks.add_all( other.callbacks )
+ supers.add_all( other.supers )
+ types.add_all( other.types )
+ casts.add_all( other.casts )
+ end
+end
+
+redef class AExternPropdef
+ private var foreign_callbacks_cache: nullable ForeignCallbackSet = null
+
+ # All foreign callbacks from this method
+ fun foreign_callbacks: ForeignCallbackSet
+ do
+ var fcs = foreign_callbacks_cache
+ assert fcs != null else print "Error: attempting to access nitni callbacks before phase 'verify_nitni_callback_phase'."
+ return fcs
+ end
+
+ # Verifiy the validity of the explicit callbacks to Nit
+ # also fills the set returned by foreign_callbacks
+ fun verify_nitni_callbacks(toolcontext: ToolContext)
+ do
+ if foreign_callbacks_cache != null then return
+
+ var fcs = new ForeignCallbackSet
+
+ var mmodule = mpropdef.mclassdef.mmodule
+
+ # receiver
+ var recv_type = mpropdef.mclassdef.bound_mtype
+ fcs.types.add(recv_type)
+
+ # return type
+ var rmt = mpropdef.msignature.return_mtype
+ if rmt != null then
+ if rmt isa MParameterType or rmt isa MVirtualType then
+ var mclass_type = mpropdef.mclassdef.bound_mtype
+ rmt = rmt.anchor_to(mmodule, mclass_type)
+ end
+ var mtype = rmt.resolve_for(recv_type, recv_type, mmodule, true)
+ fcs.types.add(mtype)
+ end
+
+ # params
+ for p in mpropdef.msignature.mparameters do
+ var mtype = p.mtype.resolve_for(recv_type, recv_type, mmodule, true)
+ if mtype isa MParameterType or mtype isa MVirtualType then
+ var mclass_type = mpropdef.mclassdef.bound_mtype
+ mtype = mtype.anchor_to(mmodule, mclass_type)
+ end
+ fcs.types.add( mtype )
+ end
+
+ # explicit callbacks
+ if n_extern_calls != null then
+ for ec in n_extern_calls.n_extern_calls do
+ ec.verify_and_collect(self, fcs, toolcontext)
+ end
+ end
+
+ # store result
+ foreign_callbacks_cache = fcs
+ end
+
+ redef fun accept_rapid_type_visitor(v)
+ do
+ for cb in foreign_callbacks.callbacks do v.add_send(cb.recv_mtype, cb.mproperty.as(MMethod))
+ for cast in foreign_callbacks.casts do v.add_cast_type(cast.to)
+ for sup in foreign_callbacks.supers do
+ v.analysis.add_super_send(sup.from.mclassdef.mclass.mclass_type, sup.from.as(MMethodDef))
+ end
+ for t in foreign_callbacks.types do if t isa MClassType then v.add_type t
+ end
+end
+
+# Classification for all nitni callbacks
+interface NitniCallback
+end
+
+redef class MType
+ super NitniCallback
+end
+
+# A prossible call from C, declared explictly after the `import` keyword
+class MExplicitCall
+ super NitniCallback
+
+ # Previously resolved mtype
+ var recv_mtype: MClassType
+ var mproperty: MProperty
+ var from_mmodule: MModule
+
+ fun fill_type_for( callback_set: ForeignCallbackSet, from: MModule )
+ do
+ var first = mproperty.lookup_first_definition( from, recv_mtype )
+ var mclassdef = first.mclassdef
+ var bound_mtype = mclassdef.bound_mtype
+
+ # receiver / constructor return
+ recv_mtype = recv_mtype.resolve_for(bound_mtype, bound_mtype, from, true)
+ recv_mtype = recv_mtype.anchor_to(from, bound_mtype)
+ callback_set.types.add( recv_mtype )
+
+ if first isa MMethodDef then
+ var rmt = first.msignature.return_mtype
+ if rmt != null then
+ rmt = rmt.resolve_for(bound_mtype, bound_mtype, from, true)
+ rmt = rmt.anchor_to(from, bound_mtype)
+ callback_set.types.add( rmt )
+ end
+
+ for p in first.msignature.mparameters do
+ var param_mtype = p.mtype.resolve_for(recv_mtype, recv_mtype, from, true)
+ param_mtype = param_mtype.resolve_for(bound_mtype, bound_mtype, from, true)
+ param_mtype = param_mtype.anchor_to(from, bound_mtype)
+ callback_set.types.add( param_mtype )
+ end
+ end
+ end
+
+ # Signature of this call in C as seen by user
+ fun csignature: String
+ do
+ var mproperty = self.mproperty
+ if mproperty isa MMethod then
+ var signature = mproperty.intro.msignature
+ assert signature != null
+
+ var creturn_type
+ if mproperty.is_init then
+ creturn_type = recv_mtype.cname
+ else if signature.return_mtype != null then
+ var ret_mtype = signature.return_mtype
+ ret_mtype = ret_mtype.resolve_for(recv_mtype, recv_mtype, from_mmodule, true)
+ creturn_type = ret_mtype.cname
+ else
+ creturn_type = "void"
+ end
+
+ var cname
+ if mproperty.is_init then
+ if mproperty.name == "init" or mproperty.name == "new" then
+ cname = "new_{recv_mtype.mangled_cname}"
+ else
+ cname = "new_{recv_mtype.mangled_cname}_{mproperty.short_cname}"
+ end
+ else
+ cname = "{recv_mtype.mangled_cname}_{mproperty.short_cname}"
+ end
+
+ var cparams = new List[String]
+ if not mproperty.is_init then
+ cparams.add( "{recv_mtype.cname} self" )
+ end
+ for p in signature.mparameters do
+ var param_mtype = p.mtype.resolve_for(recv_mtype, recv_mtype, from_mmodule, true)
+ cparams.add( "{param_mtype.cname} {p.name}" )
+ end
+
+ return "{creturn_type} {cname}( {cparams.join(", ")} )"
+ else
+ print "Type of callback from foreign code not yet supported."
+ abort
+ end
+ end
+
+ redef fun hash do return recv_mtype.hash + 1024 * mproperty.hash
+ redef fun ==(o) do return o isa MExplicitCall and recv_mtype == o.recv_mtype and mproperty == o.mproperty
+end
+
+class MExplicitSuper
+ super NitniCallback
+
+ var from: MPropDef
+
+ redef fun hash do return from.hash
+ redef fun ==(o) do return o isa MExplicitSuper and from == o.from
+end
+
+class MExplicitCast
+ super NitniCallback
+
+ var from: MType
+ var to: MType
+
+ fun check_cname: String do return "{from.mangled_cname}_is_a_{to.mangled_cname}"
+
+ fun cast_cname: String do return "{from.mangled_cname}_as_{to.mangled_cname}"
+
+ redef fun hash do return from.hash + 1024 * to.hash
+ redef fun ==(o) do return o isa MExplicitCast and from == o.from and to == o.to
+end
+
+redef class AExternCall
+ # Verify this explicit declaration of call from C and collect all relevant callbacks
+ fun verify_and_collect(npropdef: AExternPropdef, callback_set: ForeignCallbackSet,
+ toolcontext: ToolContext) is abstract
+end
+
+redef class ALocalPropExternCall
+ redef fun verify_and_collect(npropdef, callback_set, toolcontext)
+ do
+ var mmodule = npropdef.mpropdef.mclassdef.mmodule
+ var mclass_type = npropdef.mpropdef.mclassdef.bound_mtype
+ var m_name = n_methid.collect_text
+ var method = toolcontext.modelbuilder.try_get_mproperty_by_name2( self,
+ mmodule, mclass_type, m_name )
+
+ if method == null then
+ toolcontext.error(location, "Local method {m_name} not found.")
+ return
+ end
+
+ var explicit_call = new MExplicitCall(mclass_type, method, mmodule)
+ callback_set.callbacks.add(explicit_call)
+
+ explicit_call.fill_type_for(callback_set, mmodule)
+ end
+end
+
+redef class AFullPropExternCall
+ redef fun verify_and_collect(npropdef, callback_set, toolcontext)
+ do
+ var mmodule = npropdef.mpropdef.mclassdef.mmodule
+ var mclassdef = npropdef.mpropdef.mclassdef
+ var nclassdef = toolcontext.modelbuilder.mclassdef2nclassdef[mclassdef]
+ var mclass_type = mclassdef.bound_mtype
+ var mtype = toolcontext.modelbuilder.resolve_mtype(nclassdef, n_type)
+
+ if mtype == null then return
+
+ if mtype isa MParameterType or mtype isa MVirtualType then
+ mtype = mtype.anchor_to(mmodule, mclass_type)
+ end
+
+ if mtype isa MNullableType then
+ toolcontext.error(location, "Type {n_type.collect_text} is nullable and thus cannot be the receiver." )
+ return
+ end
+
+ var m_name = n_methid.collect_text
+ var method = toolcontext.modelbuilder.try_get_mproperty_by_name2( self,
+ mmodule, mtype, m_name )
+
+ if method == null then
+ toolcontext.error(location, "Method {m_name} not found in {n_type.collect_text}." )
+ return
+ end
+
+ var explicit_call = new MExplicitCall(mtype.as(MClassType), method, mmodule)
+ callback_set.callbacks.add(explicit_call)
+ explicit_call.fill_type_for(callback_set, mmodule)
+ end
+end
+
+redef class AInitPropExternCall
+ redef fun verify_and_collect(npropdef, callback_set, toolcontext)
+ do
+ var mmodule = npropdef.mpropdef.mclassdef.mmodule
+ var mclassdef = npropdef.mpropdef.mclassdef
+ var nclassdef = toolcontext.modelbuilder.mclassdef2nclassdef[mclassdef]
+ var mtype = toolcontext.modelbuilder.resolve_mtype(nclassdef, n_type)
+ if mtype == null then return
+
+ if not mtype isa MClassType then
+ toolcontext.error(location, "Type {n_type.collect_text} is not a class and thus cannot be used to instanciate a new instance." )
+ return
+ end
+
+ var meth_name = "init"
+ var meth = toolcontext.modelbuilder.try_get_mproperty_by_name2( self,
+ mmodule, mtype, meth_name )
+
+ if meth == null then
+ toolcontext.error(location, "Method {meth_name} not found in {n_type.collect_text}." )
+ return
+ end
+
+ var explicit_call = new MExplicitCall(mtype, meth, mmodule)
+ callback_set.callbacks.add(explicit_call)
+ explicit_call.fill_type_for(callback_set, mmodule)
+ end
+end
+
+redef class ASuperExternCall
+ redef fun verify_and_collect(npropdef, callback_set, toolcontext)
+ do
+ callback_set.supers.add( new MExplicitSuper( npropdef.mpropdef.as(not null) ) )
+ callback_set.types.add( npropdef.mpropdef.mclassdef.mclass.mclass_type )
+ end
+end
+
+redef class ACastExternCall
+ fun from_mtype: MType is abstract
+ fun to_mtype: MType is abstract
+
+ redef fun verify_and_collect(npropdef, callback_set, toolcontext)
+ do
+ var from = from_mtype
+ var to = to_mtype
+
+ callback_set.types.add(from)
+ callback_set.types.add(to)
+
+ callback_set.casts.add(new MExplicitCast(from, to))
+ end
+end
+
+redef class ACastAsExternCall
+ redef fun from_mtype do return n_from_type.mtype.as(not null)
+ redef fun to_mtype do return n_to_type.mtype.as(not null)
+
+ redef fun verify_and_collect(npropdef, callback_set, toolcontext)
+ do
+ var parent_aclassdef = npropdef.parent.as(AClassdef)
+ toolcontext.modelbuilder.resolve_mtype_unchecked(parent_aclassdef, n_from_type, true)
+ toolcontext.modelbuilder.resolve_mtype_unchecked(parent_aclassdef, n_to_type, true)
+ super
+ end
+end
+
+redef class AAsNullableExternCall
+ redef fun from_mtype do return n_type.mtype.as(not null)
+ redef fun to_mtype do return n_type.mtype.as_nullable
+
+ redef fun verify_and_collect(npropdef, callback_set, toolcontext)
+ do
+ var parent_aclassdef = npropdef.parent.as(AClassdef)
+ toolcontext.modelbuilder.resolve_mtype_unchecked(parent_aclassdef, n_type, true)
+ super
+ end
+end
+
+redef class AAsNotNullableExternCall
+ redef fun from_mtype do return n_type.mtype.as_nullable
+ redef fun to_mtype do
+ var mtype = n_type.mtype.as(not null)
+ if mtype isa MNullableType then return mtype.mtype
+ return mtype
+ end
+
+ redef fun verify_and_collect(npropdef, callback_set, toolcontext)
+ do
+ var parent_aclassdef = npropdef.parent.as(AClassdef)
+ toolcontext.modelbuilder.resolve_mtype_unchecked(parent_aclassdef, n_type, true)
+ super
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2013 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Support utilities to use nitni and the FFI
+import nitni_base
+
+redef class MMethod
+ # Build a C function name for the FFI implementation (uses friendly naming).
+ # * On a specific static receiver mype `recv_mtype`
+ # * In referene to the module `from_module` (used for type resolving and as a possible prefix)
+ # * Has a possible `suffix` to the method name (may be "__super", "__impl", null, etc.)
+ # * With a specified length indicating whether it uses the sort name or the long name with
+ # the module name as prefix
+ fun build_cname(recv_mtype: MClassType, from_mmodule: MModule, suffix: nullable String, length: SignatureLength): String
+ do
+ var cname
+ if self.is_init then
+ if self.name == "init" or self.name == "new" then
+ cname = "new_{recv_mtype.mangled_cname}"
+ else
+ cname = "new_{recv_mtype.mangled_cname}_{self.short_cname}"
+ end
+ else
+ cname = "{recv_mtype.mangled_cname}_{self.short_cname}"
+ end
+
+ if suffix != null then cname = "{cname}{suffix}"
+
+ if length.long then cname = "{from_mmodule.name}___{cname}"
+
+ return cname
+ end
+
+ # Build a C function signature for the FFI implementation (uses friendly naming).
+ # * On a specific static receiver mype `recv_mtype`
+ # * In referene to the module `from_module` (used for type resolving and as a possible prefix)
+ # * Has a possible `suffix` to the method name (may be "__super", "__impl", null, etc.)
+ # * With a specified length indicating whether it uses the sort name or the long name with
+ # the module name as prefix
+ # * The `call_context` identifying which types and casts to use (see `CallContext` and its instances)
+ fun build_csignature(recv_mtype: MClassType, from_mmodule: MModule, suffix: nullable String, length: SignatureLength, call_context: CallContext): String
+ do
+ var signature = self.intro.msignature
+ assert signature != null
+
+ var creturn_type
+ if self.is_init then
+ creturn_type = call_context.name_mtype(recv_mtype)
+ else if signature.return_mtype != null then
+ var ret_mtype = signature.return_mtype
+ ret_mtype = ret_mtype.resolve_for(recv_mtype, recv_mtype, from_mmodule, true)
+ creturn_type = call_context.name_mtype(ret_mtype)
+ else
+ creturn_type = "void"
+ end
+
+ var cname = build_cname(recv_mtype, from_mmodule, suffix, length)
+
+ var cparams = new List[String]
+ if not self.is_init then
+ cparams.add( "{call_context.name_mtype(recv_mtype)} recv" )
+ end
+ for p in signature.mparameters do
+ var param_mtype = p.mtype.resolve_for(recv_mtype, recv_mtype, from_mmodule, true)
+ cparams.add( "{call_context.name_mtype(param_mtype)} {p.name}" )
+ end
+
+ return "{creturn_type} {cname}( {cparams.join(", ")} )"
+ end
+
+ # Build a C function call for the FFI implementation (uses friendly naming).
+ # * On a specific static receiver mype `recv_mtype`
+ # * In referene to the module `from_module` (used for type resolving and as a possible prefix)
+ # * Has a possible `suffix` to the method name (may be "__super", "__impl", null, etc.)
+ # * With a specified length indicating whether it uses the sort name or the long name with
+ # the module name as prefix
+ # * The `call_context` identifying which types and casts to use (see `CallContext` and its instances)
+ # * Possible suffix to the parameters `param_suffix`
+ fun build_ccall(recv_mtype: MClassType, from_mmodule: MModule, suffix: nullable String, length: SignatureLength, call_context: CallContext, param_suffix: nullable String): String
+ do
+ if param_suffix == null then param_suffix = ""
+
+ var signature = self.intro.msignature
+ assert signature != null
+
+ var return_mtype = null
+ if self.is_init then
+ return_mtype = recv_mtype
+ else if signature.return_mtype != null then
+ return_mtype = signature.return_mtype
+ end
+
+ var cname = build_cname(recv_mtype, from_mmodule, suffix, length)
+
+ var cparams = new List[String]
+ if not self.is_init then
+ cparams.add(call_context.cast_to(recv_mtype, "recv{param_suffix}"))
+ end
+
+ for p in signature.mparameters do
+ cparams.add(call_context.cast_to(p.mtype, "{p.name}{param_suffix}"))
+ end
+
+ var joined_cparams = cparams.join(", ")
+ var ccall = "{cname}({joined_cparams})"
+ if return_mtype != null then
+ return "return {call_context.cast_from(return_mtype, ccall)};"
+ else
+ return "{ccall};"
+ end
+ end
+end
+
+# Describes the context of the code to be generated by `build_ccall` and `build_csignature`
+class CallContext
+ # Which C name to use for type `mtype`
+ fun name_mtype(mtype: MType): String do return mtype.cname_blind
+
+ # How to cast a returned C variable named `name` of type `mtype`
+ fun cast_from(mtype: MType, name: String): String do return name
+
+ # How to cast a C argument named `name` of type `mtype`
+ fun cast_to(mtype: MType, name: String): String do return name
+end
+
+redef class Object
+ # Call context to use
+ protected fun internal_call_context: CallContext do return new CallContext
+ protected fun long_signature: SignatureLength do return once new SignatureLength(true)
+ protected fun short_signature: SignatureLength do return once new SignatureLength(false)
+end
+
+# Length of the signature of a C function (long version hase the module name as prefix)
+class SignatureLength
+ private var long: Bool
+ private init(long: Bool) do self.long = long
+end
else
var category = parts[0]
var keyword = parts[1]
- if keyword.first == ' ' then keyword = keyword.substring_from(1)
+ if keyword.chars.first == ' ' then keyword = keyword.substring_from(1)
return new IndexQueryPair(str, keyword, category)
end
end
private fun escape: String
do
var b = new Buffer
- for c in self do
+ for c in self.chars do
if c == '\n' then
b.append("\\n")
else if c == '\0' then
if sp >= string_len then
dfa_state = -1
else
- var c = string[sp].ascii
+ var c = string.chars[sp].ascii
sp += 1
var cr = _cr
if sp >= string_len then
dfa_state = -1
else
- var c = string[sp].ascii
+ var c = string.chars[sp].ascii
sp += 1
var cr = _cr
import layout_builders
import rapid_type_analysis
import collect_super_sends
+import compiler_ffi
# Add separate compiler specific options
redef class ToolContext
end
print "\t{total}\t{holes}"
end
+
+ redef fun compile_nitni_structs
+ do
+ self.header.add_decl("struct nitni_instance \{struct instance *value;\};")
+ end
+
+ redef fun finalize_ffi_for_module(nmodule)
+ do
+ self.mainmodule = nmodule.mmodule.as(not null)
+ super
+ end
end
# A visitor on the AST of property definition that generate the C code of a separate compilation process.
end
self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
return res
+ else if value.mtype.cname_blind == "void*" and mtype.cname_blind == "void*" then
+ return value
else
# Bad things will appen!
var res = self.new_var(mtype)
var need_help = false
var no_file = false
-while not args.is_empty and args.first.first == '-' do
+while not args.is_empty and args.first.chars.first == '-' do
if args.first == "-n" then
no_print = true
else if args.first == "-l" then
end
# FIXME: covariance of return type in linear extension?
var superprop = superprops.first
- assert superprop isa MMethodDef
var msignature = v.resolve_signature_for(superprop, recvtype, true)
var args = self.n_args.to_a
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import end
+
+class A
+ fun foo do end
+end
+
+class B
+ super A
+
+ redef fun foo do end
+
+ redef fun foo do end
+
+end
+
redef class String
redef fun output
do
- for c in self do c.output
+ for c in self.chars do c.output
end
end
i = 0
for k in [0..s.length[ do
- var c = s[k]
+ var c = s.chars[k]
if c >= 'a' and c <= 'z' then
i = i + 1
end
do
var result = new Buffer
var i = 0
- while i < s.length and s[i] != ' ' do
- result.add(s[i])
+ while i < s.length and s.chars[i] != ' ' do
+ result.add(s.chars[i])
i = i + 1
end
return result.to_s
--- /dev/null
+base_error_doubledef.nit:26,12--14: Error: a property foo is already defined in class B at base_error_doubledef.nit:24,2--21
-error_ref_param.nit:20,14--17: Redef error: Expected B, as in C::r.
+error_ref_param.nit:20,14--17: Redef Error: Wrong type for parameter `x'. found C, expected B as in module_simple#C#r.
-error_ref_ret.nit:20,15--17: Redef Error: Wrong return type. found Int, expected B.
+error_ref_ret.nit:20,15--17: Redef Error: Wrong return type. found Int, expected B as in module_simple#C#s.
-error_spe_param.nit:24,16--24: Redef error: Expected Int, as in A::toto.
+error_spe_param.nit:24,16--24: Redef Error: Wrong type for parameter `c'. found Object, expected Int as in error_spe_param#A#toto.
-error_spe_param2.nit:24,16--22: Redef Error: Wrong type for parameter `c'. found Char, expected Int.
+error_spe_param2.nit:24,16--22: Redef Error: Wrong type for parameter `c'. found Char, expected Int as in error_spe_param2#A#toto.
-error_spe_ret.nit:23,17--20: Redef Error: Wrong return type. found Char, expected Int.
+error_spe_ret.nit:23,17--20: Redef Error: Wrong return type. found Char, expected Int as in error_spe_ret#A#toto.
-test_multiconstraint_inh.nit:39,18--21: Redef error: Expected I[A], as in G::baz.
+test_multiconstraint_inh.nit:39,18--21: Redef Error: Wrong type for parameter `e'. found J, expected I[G#0] as in test_multiconstraint_inh#G#baz.
TKwfalse "false" ../src/test_parser.nit:46,15--19
AWhileExpr ../src/test_parser.nit:48,1--64,3
TKwwhile "while" ../src/test_parser.nit:48,1--5
- AAndExpr ../src/test_parser.nit:48,7--51
+ AAndExpr ../src/test_parser.nit:48,7--57
ANotExpr ../src/test_parser.nit:48,7--23
TKwnot "not" ../src/test_parser.nit:48,7--9
ACallExpr ../src/test_parser.nit:48,11--23
AListExprs ../src/test_parser.nit:48,14
TId "is_empty" ../src/test_parser.nit:48,16--23
AListExprs ../src/test_parser.nit:48,23
- AEqExpr ../src/test_parser.nit:48,29--51
- ACallExpr ../src/test_parser.nit:48,29--44
- ACallExpr ../src/test_parser.nit:48,29--38
- ACallExpr ../src/test_parser.nit:48,29--32
- AImplicitSelfExpr ../src/test_parser.nit:48,29
- TId "args" ../src/test_parser.nit:48,29--32
- AListExprs ../src/test_parser.nit:48,32
- TId "first" ../src/test_parser.nit:48,34--38
- AListExprs ../src/test_parser.nit:48,38
- TId "first" ../src/test_parser.nit:48,40--44
- AListExprs ../src/test_parser.nit:48,44
- ACharExpr ../src/test_parser.nit:48,49--51
- TChar "\'-\'" ../src/test_parser.nit:48,49--51
- TKwdo "do" ../src/test_parser.nit:48,53--54
+ AEqExpr ../src/test_parser.nit:48,29--57
+ ACallExpr ../src/test_parser.nit:48,29--50
+ ACallExpr ../src/test_parser.nit:48,29--44
+ ACallExpr ../src/test_parser.nit:48,29--38
+ ACallExpr ../src/test_parser.nit:48,29--32
+ AImplicitSelfExpr ../src/test_parser.nit:48,29
+ TId "args" ../src/test_parser.nit:48,29--32
+ AListExprs ../src/test_parser.nit:48,32
+ TId "first" ../src/test_parser.nit:48,34--38
+ AListExprs ../src/test_parser.nit:48,38
+ TId "chars" ../src/test_parser.nit:48,40--44
+ AListExprs ../src/test_parser.nit:48,44
+ TId "first" ../src/test_parser.nit:48,46--50
+ AListExprs ../src/test_parser.nit:48,50
+ ACharExpr ../src/test_parser.nit:48,55--57
+ TChar "\'-\'" ../src/test_parser.nit:48,55--57
+ TKwdo "do" ../src/test_parser.nit:48,59--60
ABlockExpr ../src/test_parser.nit:49,2--64,3
AIfExpr ../src/test_parser.nit:49,2--62,4
TKwif "if" ../src/test_parser.nit:49,2--3
Read token at ../src/test_parser.nit:48,33 text='.'
Read token at ../src/test_parser.nit:48,34--38 text='first'
Read token at ../src/test_parser.nit:48,39 text='.'
-Read token at ../src/test_parser.nit:48,40--44 text='first'
-Read token at ../src/test_parser.nit:48,46--47 text='=='
-Read token at ../src/test_parser.nit:48,49--51 text=''-''
-Read token at ../src/test_parser.nit:48,53--54 text='do'
-Read token at ../src/test_parser.nit:48,55--49,0 text='
+Read token at ../src/test_parser.nit:48,40--44 text='chars'
+Read token at ../src/test_parser.nit:48,45 text='.'
+Read token at ../src/test_parser.nit:48,46--50 text='first'
+Read token at ../src/test_parser.nit:48,52--53 text='=='
+Read token at ../src/test_parser.nit:48,55--57 text=''-''
+Read token at ../src/test_parser.nit:48,59--60 text='do'
+Read token at ../src/test_parser.nit:48,61--49,0 text='
'
Read token at ../src/test_parser.nit:49,2--3 text='if'
Read token at ../src/test_parser.nit:49,5--8 text='args'
+++ /dev/null
-Je suis ici.
-Je suis ici.Je suis ici.Je suis ici.
-Je suis ici.Je suis ici.Je suis ici.Je suis ici.Je suis ici.
-Je suis ici.Je suis ici.
-Je su
-je suis ici.hi !je suis ici.hi !
-JE SUIS ICI.HI !JE SUIS ICI.HI !
var count = 0
var array = new Buffer.with_capacity(n)
for i in [0..n[ do
- array[i] = 'o'
+ array.chars[i] = 'o'
end
for i in [2..n[ do
- if array[i] == 'o' then
+ if array.chars[i] == 'o' then
var j = i * 2
while j < n do
- array[j] = 'x'
+ array.chars[j] = 'x'
j = j + i
end
count = count + 1
referenced_str = null
end
- fun get_c_string import String::items, NativeString::to_s, NativeString::to_s_with_copy, StringTest::ref_test, StringTest::copy_test `{
+ fun get_c_string import String.items, NativeString.to_s, NativeString.to_s_with_copy, StringTest.ref_test, StringTest.copy_test `{
char* string = "This is a test string";
String ref_string = NativeString_to_s(string);
var w : String = "w"
var rw : String = "rw"
- fun print_all import String::to_cstring, r, rw `{
+ fun print_all import String.to_cstring, r, rw `{
printf( "%s %s\n",
String_to_cstring( A_r( recv ) ),
String_to_cstring( A_rw( recv ) ) );
`}
- fun modify import NativeString::to_s, w=, rw= `{
+ fun modify import NativeString.to_s, w=, rw= `{
A_w__assign( recv, NativeString_to_s( "w set from native" ) );
A_rw__assign( recv, NativeString_to_s( "rw set from native" ) );
`}
end
class B
- fun print_and_modify( a : A ) import A::rw, A::rw=, String::to_cstring, NativeString::to_s `{
+ fun print_and_modify( a : A ) import A.rw, A.rw=, String.to_cstring, NativeString.to_s `{
printf( "%s\n", String_to_cstring( A_rw( a ) ) );
A_rw__assign( a, NativeString_to_s( "set from native" ) );
printf( "%s\n", String_to_cstring( A_rw( a ) ) );
return foobar;
`}
- fun test_me is extern import Test::foo, NativeString::to_s `{
+ fun test_me is extern import Test.foo, NativeString.to_s `{
int i;
for(i = 0; i < 2000; ++i) {
printf("%d\n", i);
Object_foo(recv);
`}
-fun call_a_constructor import A, A::bar `{
+fun call_a_constructor import A, A.bar `{
A a = new_A();
A_bar(a);
`}
redef fun foo do print self
end
-fun callbacks_with_as_casts(a: A, b: B) import B::foo, A::foo, B as(A), A as(B) `{
+fun callbacks_with_as_casts(a: A, b: B) import B.foo, A.foo, B.as(A), A.as(B) `{
A_foo(a);
B_foo(b);
B_foo(bb);
`}
-fun callbacks_with_nullable_casts(a: A, b: nullable B) import B as not nullable, A as nullable, A as(nullable B), B::foo `{
+fun callbacks_with_nullable_casts(a: A, b: nullable B) import B as not nullable, A as nullable, A.as(nullable B), B.foo `{
if (!nullable_B_is_a_B(b)) {
printf("Instance b is not a B (it is null)\n");
} else {
}
`}
-fun callbacks_with_failed_checks(a: A, b: nullable B) import B as not nullable, B as nullable, A as(B), B as (A) `{
+fun callbacks_with_failed_checks(a: A, b: nullable B) import B as not nullable, B as nullable, A.as(B), B.as(A) `{
if (!A_is_a_B(a)) {
printf("Instance of A is not a B.\n");
}
}
`}
-fun callbacks_with_primitives(o: Object, i: Int, ni: nullable Int) import Object as(Int), Int as(Object), nullable Int as(Int), Int::foo, Object::foo `{
+fun callbacks_with_primitives(o: Object, i: Int, ni: nullable Int) import Object.as(Int), Int.as(Object), nullable Int.as(Int), Int.foo, Object.foo `{
Object_foo(o);
Int_foo(i);
end
class A
- fun save_as_global( tbp : ToBePreserved, i : Int ) import ToBePreserved::output `{
+ fun save_as_global( tbp : ToBePreserved, i : Int ) import ToBePreserved.output `{
if ( global_tbps[i] != NULL )
ToBePreserved_decr_ref( global_tbps[i] );
fun m : Int is extern `{ return 10; `}
- fun n : String is extern import NativeString::to_s `{
+ fun n : String is extern import NativeString.to_s `{
return NativeString_to_s( "allo" );
`}
- fun o ( str : String ) is extern import String::to_cstring `{
+ fun o ( str : String ) is extern import String.to_cstring `{
f( String_to_cstring( str ) );
`}
fun in1(i: Int) do print "Back in Nit: in1 {i}"
fun in2(i: Float) do print "Back in Nit: in2"
-fun out(i: Int, f: Float): Int import in1, in2, A, A::alt, A::to_i `{
+fun out(i: Int, f: Float): Int import in1, in2, A, A.alt, A.to_i `{
printf("From C, beginning out: %ld\n", i);
Object_in1(recv, i);
A a = new_A();
return new_A( s / by );
`}
- redef fun ==( other ) import value, nullable Object as(A) `{
+ redef fun ==( other ) import value, nullable Object.as(A) `{
if ( nullable_Object_is_a_A( other ) &&
A_value( nullable_Object_as_A(other) ) == A_value( recv ) )
return 1;
return "char* from C";
`}
-fun print_string(str: String) import String::to_cstring `{
+fun print_string(str: String) import String.to_cstring `{
printf("str-> %s\n", String_to_cstring(str) );
`}
-fun get_string: String import NativeString::to_s, String::output `{
+fun get_string: String import NativeString.to_s, String.output `{
String str = NativeString_to_s("Nit string from C");
String_output(str);
printf("\n");
class B
super A
- redef fun id : String import super, NativeString::to_s, String::to_cstring `{
+ redef fun id : String import super, NativeString.to_s, String.to_cstring `{
char *new_name;
char *prefix = "B special ";
char *super_name = String_to_cstring( B_id___super( recv ) );
+++ /dev/null
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# This file is free software, which comes along with NIT. This software is
-# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE. You can modify it if you want, provided this header
-# is kept unaltered, and a notification of the changes is added.
-# You are allowed to redistribute it and sell it, alone or as a part of
-# another product.
-
-module test_ropes
-
-var str_part_1 = "Je"
-
-var str_part_2 = "suis"
-
-var str_part_3 = "ici"
-
-var str_part_4 = "."
-
-var space = " "
-
-var test = "Je suis ici."
-
-var rope_uniq_test = new ImmutableRope.with_string("zzzzzzzzzzzzzzzzzzzzzzzzzzzz")
-
-var not_rope_uniq_test = new ImmutableRope.with_string("zzzzzzzzzzzzzezzzzzzzzzzzzzz")
-
-################################
-# Rope methods tests #
-################################
-
-var buf = new Buffer
-
-buf.append(str_part_1)
-buf.append(space)
-buf.append(str_part_2)
-buf.append(space)
-buf.append(str_part_3)
-buf.append(str_part_4)
-
-print buf
-
-var buf_rope = new BufferRope
-
-buf_rope.append_multi(str_part_1,space,str_part_2,space,str_part_3,str_part_4)
-
-var buf_rope_with_str = new BufferRope.with_string(test)
-
-print buf_rope*3
-
-print buf_rope_with_str*5
-
-print buf_rope + buf_rope_with_str
-
-assert buf_rope.length == buf_rope_with_str.length
-
-assert buf_rope == buf_rope_with_str
-
-assert buf_rope.multi_concat(buf_rope, buf_rope) == buf_rope * 3
-
-print buf_rope.subrope(0, 5)
-
-assert buf_rope.subrope(0, 5) == "Je su"
-
-buf_rope.append("Hi !")
-
-assert buf_rope > buf_rope_with_str
-
-assert buf_rope == buf_rope.chars.to_s
-
-assert buf_rope.chars.to_s == buf_rope
-
-assert buf == buf_rope_with_str
-
-######################################
-# BufferRope methods tests #
-######################################
-
-assert buf_rope + buf_rope == buf_rope.concat(buf_rope)
-
-assert buf_rope == buf_rope.freeze
-
-######################################
-# Rope.chars methods tests #
-######################################
-
-assert buf_rope.chars[3] == 's'
-
-assert buf_rope.chars.index_of('k') == -1
-
-assert buf_rope.chars.index_of('s') == 3
-
-assert buf_rope.chars.count('s') == 4
-
-assert buf_rope.chars.last == '!'
-
-assert rope_uniq_test.chars.has_only('z')
-
-assert not not_rope_uniq_test.chars.has_only('z')
-
-assert (new BufferRope).chars.has_only('l')
-
-print buf_rope.to_lower
-
-print buf_rope.to_upper
-
-
fun test(s: String)
do
print s.length
- print s.first
- print s.last
- print s[2]
+ print s.chars.first
+ print s.chars.last
+ print s.chars[2]
print s.substring(1, 2)
print s.substring(-1, 2)
print s.substring(1, 0)
while i < 5000 do
var j = 0
while j < s.length do
- r.add(s[j])
- r2.add(s[j])
+ r.add(s.chars[j])
+ r2.add(s.chars[j])
j = j + 1
end
i = i + 1
var a = "éè"
print(a.length)
for i in [0..a.length[ do
- print("{i} is {a[i]} ({a[i].ascii})")
+ print("{i} is {a.chars[i]} ({a.chars[i].ascii})")
end
var test = "test"
-print("test[0] == 't' => {test[0] == 't'}")
-print("test[1] == 'e' => {test[1] == 'e'}")
-print("test[2] == 's' => {test[2] == 's'}")
-print("test[3] == 't' => {test[3] == 't'}")
+print("test[0] == 't' => {test.chars[0] == 't'}")
+print("test[1] == 'e' => {test.chars[1] == 'e'}")
+print("test[2] == 's' => {test.chars[2] == 's'}")
+print("test[3] == 't' => {test.chars[3] == 't'}")
print("test.substring(0,1) == \"t\" => {test.substring(0,1) == "t"}")
print("test.substring(0,2) == \"te\" => {test.substring(0,2) == "te"}")