e0cd788b27a7235507d716d6bbfd532d04c5587b
[nit.git] / src / ffi / light_c.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2012-2014 Alexis Laferrière <alexis.laf@xymus.net>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Support for nesting C code within a Nit program using its FFI
18 module light_c
19
20 import modelize::modelize_property
21
22 import light_ffi_base
23
24 redef class FFILanguageAssignationPhase
25 var c_language: FFILanguage = new CLanguage(self)
26 end
27
28 class CLanguage
29 super FFILanguage
30
31 redef fun identify_language(n) do return n.is_c
32
33 redef fun compile_module_block(block, ecc, mmodule)
34 do
35 if block.is_c_header then
36 ecc.header_custom.add block.location.as_line_pragma
37 ecc.header_custom.add "\n"
38 ecc.header_custom.add block.code
39 else if block.is_c_body then
40 ecc.body_impl.add block.location.as_line_pragma
41 ecc.body_impl.add "\n"
42 ecc.body_impl.add block.code
43 end
44 end
45
46 redef fun compile_extern_method(block, m, ecc, mmodule)
47 do
48 var fc = new ExternCFunction(m, mmodule)
49 fc.decls.add( block.location.as_line_pragma )
50 fc.exprs.add( block.code )
51 ecc.body_impl.add fc.to_writer
52 end
53
54 redef fun compile_extern_class(block, m, ecc, mmodule) do end
55
56 redef fun get_ftype(block, m) do return new ForeignCType(block.code)
57 end
58
59 redef class AExternCodeBlock
60 fun is_c: Bool do return language_name == null or
61 language_name_lowered == "c" or language_name_lowered.has_prefix( "c " )
62
63 fun is_c_body: Bool do return language_name == null or
64 language_name_lowered == "c" or language_name_lowered == "c body"
65
66 fun is_c_header: Bool do return language_name_lowered == "c header"
67 end
68
69 redef class Location
70 fun as_line_pragma: String do return "#line {line_start-1} \"{file.filename}\"\n"
71 end
72
73 redef class MModule
74 # FIXME make nullable the key of `cflags`, `ldflags` and `cppflags` when
75 # supported by the bootstrap
76
77 # Custom options for the C compiler (CFLAGS)
78 var cflags = new MultiHashMap[String, String]
79
80 # Custom options for the C linker (LDFLAGS)
81 var ldflags = new MultiHashMap[String, String]
82
83 # Additional libraries needed for the compilation
84 # Will be used with pkg-config
85 var pkgconfigs = new Array[String]
86 end
87
88 class ForeignCType
89 super ForeignType
90
91 redef var ctype: String
92 end
93
94 redef class Object
95 # Context when calling user C code from generated code
96 fun to_c_call_context: ToCCallContext do return once new ToCCallContext
97
98 # Context when calling generated code from user C code
99 fun from_c_call_context: FromCCallContext do return once new FromCCallContext
100 end
101
102 # Context when calling user C code from generated code
103 class ToCCallContext
104 super CallContext
105
106 # TODO: private init because singleton instance (see `to_c_call_context`)
107
108 redef fun name_mtype(mtype)
109 do
110 if mtype isa MClassType and mtype.mclass.kind == extern_kind then return "void *"
111 return mtype.cname
112 end
113 end
114
115 # Context when calling generated code from user C code
116 class FromCCallContext
117 super CallContext
118
119 # TODO: private init because singleton instance (see `from_c_call_context`)
120
121 redef fun name_mtype(mtype) do return mtype.cname
122 end
123
124 class ExternCFunction
125 super CFunction
126
127 var method: AMethPropdef
128
129 init (method: AMethPropdef, mmodule: MModule)
130 do
131 self.method = method
132
133 var recv_mtype = method.mpropdef.mclassdef.bound_mtype
134 var csignature = method.mpropdef.mproperty.build_csignature(recv_mtype, mmodule, "___impl", long_signature, from_c_call_context)
135
136 super( csignature )
137 end
138 end