Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/compiler/abstract_compiler.nit
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import platform
import c_tools
private import annotation
import mixin
import define
import counter
import pkgconfig
private import explain_assert_api
Expand Down
103 changes: 103 additions & 0 deletions src/define.nit
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# 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.

# Top-level function refinements at link-time.
module define

import mixin

redef class ToolContext
# --define
var opt_defines = new OptionArray("Define a specific property", "-D", "--define")

redef init
do
super
option_context.add_option(opt_defines)
end

redef fun make_main_module(mmodules)
do
var mainmodule = super

var defines = opt_defines.value
if not defines.is_empty then
var location = mainmodule.location
var model = mainmodule.model

# Create a fictive module if needed
if mainmodule == mmodules.first then
mainmodule = new MModule(model, null, mainmodule.name + "-d", location)
mainmodule.set_imported_mmodules(mmodules)
mainmodule.is_fictive = true
mainmodule.first_real_mmodule = mmodules.first
end

var recv = mainmodule.sys_type
assert recv != null
var mclassdef = new MClassDef(mainmodule, recv, location)
mclassdef.add_in_hierarchy

for define in defines do
var spl = define.split_once_on('=')
var name = spl.first
var val = null
if spl.length > 1 then val = spl[1]
var prop = mainmodule.try_get_primitive_method(name, recv.mclass)
if prop == null then
error(null, "Error: --define: no top-level function `{name}`.")
continue
end
var ret = prop.intro.msignature.return_mtype
var v
if ret == null then
error(null, "Error: --define: method `{prop}` is not a function.")
continue
else if ret.to_s == "Bool" then
if val == null or val == "true" then
v = true
else if val == "false" then
v = false
else
error(null, "Error: --define: method `{prop}` needs a Bool.")
continue
end
else if ret.to_s == "Int" then
if val != null and val.is_numeric then
v = val.to_i
else
error(null, "Error: --define: method `{prop}` needs a Int.")
continue
end
else if ret.to_s == "String" then
if val != null then
v = val
else
error(null, "Error: --define: method `{prop}` needs a String.")
continue
end
else
error(null, "Error: --define: method `{prop}` returns an unsupported type `{ret}`.")
continue
end
var pd = new MMethodDef(mclassdef, prop, location)
pd.msignature = prop.intro.msignature
pd.constant_value = v
end
check_errors
end

return mainmodule
end
end
1 change: 1 addition & 0 deletions src/interpreter/naive_interpreter.nit
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import literal
import semantize
private import parser::tables
import mixin
import define
private import model::serialize_model
private import frontend::explain_assert_api

Expand Down
78 changes: 3 additions & 75 deletions src/mixin.nit
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

# Loading and additional module refinements at link-time.
# Loading of additional modules at link-time.
#
# Used to factorize some code used by the engines.
module mixin
Expand All @@ -22,13 +22,11 @@ import modelbuilder
redef class ToolContext
# --mixin
var opt_mixins = new OptionArray("Additional module to mix-in", "-m", "--mixin")
# --define
var opt_defines = new OptionArray("Define a specific property", "-D", "--define")

redef init
do
super
option_context.add_option(opt_mixins, opt_defines)
option_context.add_option(opt_mixins)
end

redef fun make_main_module(mmodules)
Expand All @@ -38,76 +36,6 @@ redef class ToolContext
mmodules.add_all modelbuilder.parse(opt_mixins.value)
modelbuilder.run_phases
end

var mainmodule = super

var defines = opt_defines.value
if not defines.is_empty then
var location = mainmodule.location
var model = mainmodule.model

# Create a fictive module if needed
if mainmodule == mmodules.first then
mainmodule = new MModule(model, null, mainmodule.name + "-d", location)
mainmodule.set_imported_mmodules(mmodules)
mainmodule.is_fictive = true
mainmodule.first_real_mmodule = mmodules.first
end

var recv = mainmodule.sys_type
assert recv != null
var mclassdef = new MClassDef(mainmodule, recv, location)
mclassdef.add_in_hierarchy

for define in defines do
var spl = define.split_once_on('=')
var name = spl.first
var val = null
if spl.length > 1 then val = spl[1]
var prop = mainmodule.try_get_primitive_method(name, recv.mclass)
if prop == null then
error(null, "Error: --define: no top-level function `{name}`.")
continue
end
var ret = prop.intro.msignature.return_mtype
var v
if ret == null then
error(null, "Error: --define: method `{prop}` is not a function.")
continue
else if ret.to_s == "Bool" then
if val == null or val == "true" then
v = true
else if val == "false" then
v = false
else
error(null, "Error: --define: method `{prop}` needs a Bool.")
continue
end
else if ret.to_s == "Int" then
if val != null and val.is_numeric then
v = val.to_i
else
error(null, "Error: --define: method `{prop}` needs a Int.")
continue
end
else if ret.to_s == "String" then
if val != null then
v = val
else
error(null, "Error: --define: method `{prop}` needs a String.")
continue
end
else
error(null, "Error: --define: method `{prop}` returns an unsupported type `{ret}`.")
continue
end
var pd = new MMethodDef(mclassdef, prop, location)
pd.msignature = prop.intro.msignature
pd.constant_value = v
end
check_errors
end

return mainmodule
return super
end
end
41 changes: 26 additions & 15 deletions src/modelbuilder.nit
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,11 @@ redef class ToolContext
# Combine module to make a single one if required.
fun make_main_module(mmodules: Array[MModule]): MModule
do
assert not mmodules.is_empty
var mainmodule
# We need a main module, so we build it by importing all modules
mainmodule = new MModule(modelbuilder.model, null, mmodules.first.name + "-m", new Location(mmodules.first.location.file, 0, 0, 0, 0))
mainmodule.is_fictive = true
mainmodule.first_real_mmodule = mmodules.first.first_real_mmodule
mainmodule.set_imported_mmodules(mmodules)
modelbuilder.apply_conditional_importations(mainmodule)
if mainmodule.in_importation.direct_greaters.length == 1 and mainmodule.in_importation.direct_greaters.first == mmodules.first then
# Drop the fictive module if not needed
mainmodule = mmodules.first
else
# Or else run phases on it
modelbuilder.run_phases
end
var mainmodule = modelbuilder.combine_main_module(mmodules)

# Run phases on the fictive module if we created one
if mainmodule.is_fictive then modelbuilder.run_phases

return mainmodule
end

Expand Down Expand Up @@ -89,6 +79,27 @@ end


redef class ModelBuilder
# Combine `mmodules` into the main module of a program and apply conditional importations
#
# Create a fictive module to import all the modules, unless the first one already
# imports the others, then we can reuse it.
fun combine_main_module(mmodules: Array[MModule]): MModule
do
assert not mmodules.is_empty
var mainmodule
# We need a main module, so we build it by importing all modules
mainmodule = new MModule(model, null, mmodules.first.name + "-m", new Location(mmodules.first.location.file, 0, 0, 0, 0))
mainmodule.is_fictive = true
mainmodule.first_real_mmodule = mmodules.first.first_real_mmodule
mainmodule.set_imported_mmodules(mmodules)
apply_conditional_importations(mainmodule)
if mainmodule.in_importation.direct_greaters.length == 1 and mainmodule.in_importation.direct_greaters.first == mmodules.first then
# Drop the fictive module if not needed
mainmodule = mmodules.first
end
return mainmodule
end

# Run phases on all loaded modules
fun run_phases
do
Expand Down
7 changes: 6 additions & 1 deletion src/nitls.nit
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
module nitls

import modelbuilder
import mixin
import loader_header_only
import ordered_tree
import console
Expand Down Expand Up @@ -154,9 +155,10 @@ if sum == 0 then
end

var mmodules = mb.scan_full(files)
var mixins = mb.scan_full(tc.opt_mixins.value)

# Load modules to get more informations
for mmodule in mmodules do
for mmodule in mmodules + mixins do
if not opt_paths.value or opt_depends.value then
var ast = mmodule.parse(mb)
if ast != null and opt_depends.value then
Expand All @@ -167,6 +169,9 @@ end
#tc.check_errors

if opt_depends.value then
# Apply the conditional importations
for mmodule in mmodules do mb.combine_main_module([mmodule] + mixins)

# Extends the list of module with the loaded ones
mmodules = mb.parsed_modules.to_a
end
Expand Down
5 changes: 5 additions & 0 deletions tests/nitls.args
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,8 @@ test_prog/game/excluded.nit test_prog/game/excluded_dir/more.nit -t --no-color
-M nitls_header_redef.nit
-M error_mod_unk.nit --no-color
-M nitls_error_header.nit
-M base_module_conditional.nit
-M base_module_conditional_client.nit
-M base_module_conditional.nit module_2.nit
-M base_module_conditional.nit -m module_2.nit
-M base_module_conditional.nit module_0.nit -m module_2.nit
1 change: 1 addition & 0 deletions tests/sav/nitls_args10.res
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
base_simple.nit
base_simple_import.nit
nitls_header_annotations.nit
2 changes: 2 additions & 0 deletions tests/sav/nitls_args15.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
base_module_conditional.nit
module_0.nit
5 changes: 5 additions & 0 deletions tests/sav/nitls_args16.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
base_module_conditional.nit
base_module_conditional_client.nit
module_0.nit
module_1.nit
module_2.nit
3 changes: 3 additions & 0 deletions tests/sav/nitls_args17.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
base_module_conditional.nit
module_0.nit
module_2.nit
4 changes: 4 additions & 0 deletions tests/sav/nitls_args18.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
base_module_conditional.nit
module_0.nit
module_1.nit
module_2.nit
4 changes: 4 additions & 0 deletions tests/sav/nitls_args19.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
base_module_conditional.nit
module_0.nit
module_1.nit
module_2.nit
Loading