Merge: doc: fixed some typos and other misc. corrections
[nit.git] / src / mixin.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Loading and additional module refinements at link-time.
16 #
17 # Used to factorize some code used by the engines.
18 module mixin
19
20 import modelbuilder
21
22 redef class ToolContext
23 # --mixin
24 var opt_mixins = new OptionArray("Additional module to mix-in", "-m", "--mixin")
25 # --define
26 var opt_defines = new OptionArray("Define a specific property", "-D", "--define")
27
28 redef init
29 do
30 super
31 option_context.add_option(opt_mixins, opt_defines)
32 end
33
34 redef fun make_main_module(mmodules)
35 do
36 var mixins = opt_mixins.value
37 if not mixins.is_empty then
38 mmodules.add_all modelbuilder.parse(opt_mixins.value)
39 modelbuilder.run_phases
40 end
41
42 var mainmodule = super
43
44 var defines = opt_defines.value
45 if not defines.is_empty then
46 var location = mainmodule.location
47 var model = mainmodule.model
48
49 # Create a fictive module if needed
50 if mainmodule == mmodules.first then
51 mainmodule = new MModule(model, null, mainmodule.name + "-d", location)
52 mainmodule.set_imported_mmodules(mmodules)
53 mainmodule.is_fictive = true
54 mainmodule.first_real_mmodule = mmodules.first
55 end
56
57 var recv = mainmodule.sys_type
58 assert recv != null
59 var mclassdef = new MClassDef(mainmodule, recv, location)
60 mclassdef.add_in_hierarchy
61
62 for define in defines do
63 var spl = define.split_once_on('=')
64 var name = spl.first
65 var val = null
66 if spl.length > 1 then val = spl[1]
67 var prop = mainmodule.try_get_primitive_method(name, recv.mclass)
68 if prop == null then
69 error(null, "Error: --define: no top-level function `{name}`.")
70 continue
71 end
72 var ret = prop.intro.msignature.return_mtype
73 var v
74 if ret == null then
75 error(null, "Error: --define: method `{prop}` is not a function.")
76 continue
77 else if ret.to_s == "Bool" then
78 if val == null or val == "true" then
79 v = true
80 else if val == "false" then
81 v = false
82 else
83 error(null, "Error: --define: method `{prop}` needs a Bool.")
84 continue
85 end
86 else if ret.to_s == "Int" then
87 if val != null and val.is_numeric then
88 v = val.to_i
89 else
90 error(null, "Error: --define: method `{prop}` needs a Int.")
91 continue
92 end
93 else if ret.to_s == "String" then
94 if val != null then
95 v = val
96 else
97 error(null, "Error: --define: method `{prop}` needs a String.")
98 continue
99 end
100 else
101 error(null, "Error: --define: method `{prop}` returns an unsupported type `{ret}`.")
102 continue
103 end
104 var pd = new MMethodDef(mclassdef, prop, location)
105 pd.msignature = prop.intro.msignature
106 pd.constant_value = v
107 end
108 check_errors
109 end
110
111 return mainmodule
112 end
113 end