nitc :: Phase :: process_annotated_node
Note that the order of the visit is the one of the file @toimplement
# Specific actions to execute on annotated nodes
# Note that the order of the visit is the one of the file
# @toimplement
fun process_annotated_node(node: ANode, nat: AAnnotation) do end
src/phase.nit:254,2--257,65
redef fun process_annotated_node(nmoduledecl, nat)
do
# Skip if we are not interested
if nat.name != "pkgconfig" then return
# Do some validity checks and print errors if the annotation is used incorrectly
var modelbuilder = toolcontext.modelbuilder
if not nmoduledecl isa AModuledecl then
modelbuilder.error(nat, "Syntax Error: only the declaration of modules may use `pkgconfig`.")
return
end
# retrieve module
var nmodule = nmoduledecl.parent.as(AModule)
var mmodule = nmodule.mmodule.as(not null)
# target pkgs
var pkgs = new Array[String]
var args = nat.n_args
if args.is_empty then
# use module name
pkgs.add(mmodule.name)
else
for arg in args do
var pkg = arg.as_string
if pkg == null then
modelbuilder.error(nat, "Syntax Error: `pkgconfig` expects its arguments to be the name of the package as String literals.")
return
end
pkgs.add(pkg)
end
end
for pkg in pkgs do
mmodule.pkgconfigs.add pkg
end
end
src/ffi/pkgconfig.nit:70,2--109,4
redef fun process_annotated_node(nmoduledecl, nat)
do
# Skip if we are not interested
var annotation_name = nat.name
if annotation_name != compiler_annotation_name and
annotation_name != linker_annotation_name and
annotation_name != cpp_compiler_annotation_name then return
# Do some validity checks and print errors if the annotation is used incorrectly
var modelbuilder = toolcontext.modelbuilder
if not nmoduledecl isa AModuledecl then
modelbuilder.error(nat, "Syntax Error: only the declaration of modules may use `{annotation_name}`.")
return
end
var args = nat.n_args
if args.is_empty then
modelbuilder.error(nat, "Syntax Error: `{annotation_name}` expects at least one argument.")
return
end
var options = new Array[CCompilerOption]
for expr in args do
if expr isa AStringFormExpr then
var text = expr.collect_text
text = text.substring(1, text.length-2)
var opt = new DirectCCompilerOption(text)
options.add(opt)
else if expr isa ACallExpr then
# We support calls to "exec" only
var exec_args = expr.n_args.to_a
if expr.n_qid.n_id.text != "exec" or exec_args.is_empty then
modelbuilder.error(nat, "Syntax Error: `{annotation_name}` accepts only calls to `exec` with the command as arguments.")
return
end
var exec_args_as_strings = new Array[String]
for exec_arg in exec_args do
if not exec_arg isa AStringFormExpr then
modelbuilder.error(nat, "Syntax Error: calls to `exec` expects the arguments to be String literals.")
return
else
var arg_string = exec_arg.collect_text
arg_string = arg_string.substring(1, arg_string.length-2)
exec_args_as_strings.add(arg_string)
end
end
var opt = new ExecCCompilerOption(exec_args_as_strings, expr)
options.add(opt)
else
modelbuilder.error(nat, "Syntax Error: `{annotation_name}` expects its arguments to be the name of the package as String literals.")
return
end
end
# process calls to external command
var simplified_options = new Array[DirectCCompilerOption]
for opt in options do
if opt isa ExecCCompilerOption then
# prepare to execute command
var cmd_args = opt.command
var proc
if cmd_args.length == 1 then
proc = new ProcessReader.from_a(cmd_args[0], new Array[String])
else if cmd_args.length > 1 then
var rest_args = cmd_args.subarray(1, cmd_args.length-1)
proc = new ProcessReader.from_a(cmd_args[0], rest_args)
else abort
# wait for its completion
proc.wait
# check result
var status = proc.status
if status != 0 then
modelbuilder.error(opt.exec_node, "Error: something went wrong when executing the argument of `{annotation_name}`, make sure the command is valid.")
return
end
# process result
var result = proc.read_all.replace("\n", " ")
if result.is_empty then
modelbuilder.error(opt.exec_node, "Error: got no result from the command, make sure it is valid.")
return
end
simplified_options.add(new DirectCCompilerOption(result))
else
assert opt isa DirectCCompilerOption
simplified_options.add(opt)
end
end
# Retrieve module
var mmodule = nmoduledecl.parent.as(AModule).mmodule.as(not null)
# Get target platform from annotation on annotation
var platform = ""
## Is there an imported platform?
var target_platform = mmodule.target_platform
if target_platform != null then
platform = target_platform.name or else ""
end
## Is the platform declared explicitly?
var annots = nat.n_annotations
if annots != null then
var items = annots.n_items
if items.length > 1 then
modelbuilder.error(annots, "Syntax Error: `{annotation_name}` accepts only a single annotation, the platform name.")
return
end
assert items.length == 1
var item = items.first
platform = item.name
end
# Store the flags in the module
for opt in simplified_options do
var arg = opt.option
if annotation_name == compiler_annotation_name then
mmodule.cflags.add_one(platform, arg)
else if annotation_name == linker_annotation_name then
mmodule.ldflags.add_one(platform, arg)
else if annotation_name == cpp_compiler_annotation_name then
mmodule.cppflags.add_one(platform, arg)
else abort
end
end
src/ffi/c_compiler_options.nit:39,2--170,4
redef fun process_annotated_node(nmoduledecl, nat)
do
var annotation_name = "platform"
# Skip if we are not interested
if nat.name != annotation_name then return
# Do some validity checks and print errors if the annotation is used incorrectly
var modelbuilder = toolcontext.modelbuilder
if not nmoduledecl isa AModuledecl then
modelbuilder.error(nat, "Syntax Error: only the declaration of modules may use `{annotation_name}`.")
return
end
var args = nat.n_args
var platform_name
if args.length > 1 then
modelbuilder.error(nat, "Syntax Error: `{annotation_name}` expects at most a single argument.")
return
else if args.is_empty then
platform_name = nmoduledecl.n_name.collect_text
else
platform_name = args.first.as_string
if platform_name == null then
var format_error = "Syntax Error: `{annotation_name}` expects its argument to be the name of the target platform as a String literal."
modelbuilder.error(nat, format_error)
return
end
end
var nmodule = nmoduledecl.parent.as(AModule)
var mmodule = nmodule.mmodule
var platform = toolcontext.platform_from_name(platform_name)
if platform == null then
toolcontext.error(nat.location, "Error: target platform `{platform_name}` unknown.")
return
end
var previous_target_platform = mmodule.target_platform
if previous_target_platform != null and previous_target_platform != platform then
modelbuilder.error(nat, "Syntax Error: a target platform has already been defined as `{previous_target_platform}`.")
end
mmodule.local_target_platform = platform
end
src/platform/platform.nit:39,2--84,4
redef fun process_annotated_node(nmoduledecl, nat)
do
# Skip if we are not interested
var annot_name = "extra_java_files"
if nat.name != annot_name then return
# Do some validity checks and print errors if the annotation is used incorrectly
var modelbuilder = toolcontext.modelbuilder
if not nmoduledecl isa AModuledecl then
modelbuilder.error(nat, "Syntax Error: only the declaration of modules may use `{annot_name}`.")
return
end
var args = nat.n_args
if args.is_empty then
modelbuilder.error(nat, "Syntax Error: `{annot_name}` expects at least one argument.")
return
end
# retrieve module
var nmodule = nmoduledecl.parent.as(AModule)
var mmodule = nmodule.mmodule.as(not null)
var java_files = mmodule.extra_java_files
if java_files == null then
java_files = new Array[ExtraJavaFile]
mmodule.extra_java_files = java_files
end
var format_error = "Syntax Error: `{annot_name}` expects its arguments to be paths to java files."
for arg in args do
var name = arg.as_string
if name == null or name.is_empty then
modelbuilder.error(arg, format_error)
return
end
var path = name.split(".").last + ".java"
# Append specified path to directory of the Nit source file
var source_file = nat.location.file
if source_file != null then path = "{source_file.filename.dirname}/{path}"
if not path.file_exists then
modelbuilder.error(nat, "FFI with Java Error: file `{path}` not found.")
continue
end
var file = new ExtraJavaFile(name, path)
mmodule.ffi_files.add file
java_files.add file
end
end
src/ffi/extra_java_files.nit:38,2--90,4
redef fun process_annotated_node(node, nat)
do
var text = nat.n_atid.n_id.text
if text != "serialize_as" then return
if not node isa AAttrPropdef then
toolcontext.error(node.location,
"Syntax Error: annotation `{text}` applies only to attributes.")
return
end
# Can't use `arg_as_string` because it needs the literal phase
var args = nat.n_args
if args.length != 1 or not args.first isa AStringFormExpr then
toolcontext.error(node.location,
"Syntax Error: annotation `{text}` expects a single string literal as argument.")
return
end
var t = args.first.collect_text
var val = t.substring(1, t.length-2)
node.serialize_name = val
end
src/frontend/serialization_model_phase.nit:60,2--82,4
redef fun process_annotated_node(node, nat)
do
# Skip if we are not interested
var text = nat.n_atid.n_id.text
var serialize = text == "auto_serializable" or text == "serialize"
var noserialize = text == "noserialize"
if not (serialize or noserialize) then return
# Check legality of annotation
if node isa AModuledecl then
if noserialize then toolcontext.error(node.location, "Syntax Error: superfluous use of `{text}`, by default a module is `{text}`")
return
else if not (node isa AStdClassdef or node isa AAttrPropdef) then
toolcontext.error(node.location,
"Syntax Error: only a class, a module or an attribute can be annotated with `{text}`.")
return
else if serialize and node.is_noserialize then
toolcontext.error(node.location,
"Syntax Error: an entity cannot be both `{text}` and `noserialize`.")
return
else if node.as(Prod).get_annotations(text).length > 1 then
toolcontext.warning(node.location, "useless-{text}",
"Warning: duplicated annotation `{text}`.")
end
# Check the `serialize` state of the parent
if not node isa AModuledecl then
var up_serialize = false
var up: nullable ANode = node
while up != null do
up = up.parent
if up == null then
break
else if up.is_serialize then
up_serialize = true
break
else if up.is_noserialize then
break
end
end
# Check for useless double declarations
if serialize and up_serialize then
toolcontext.warning(node.location, "useless-serialize",
"Warning: superfluous use of `{text}`.")
else if noserialize and not up_serialize then
toolcontext.warning(node.location, "useless-noserialize",
"Warning: superfluous use of `{text}`.")
end
end
end
src/frontend/serialization_model_phase.nit:88,2--138,4
redef fun process_annotated_node(nclassdef, nat)
do
if nat.name == "auto_inspect" then
if not nclassdef isa AStdClassdef then
toolcontext.error(nclassdef.location, "Syntax Error: only a concrete class can be `{nat.name}`.")
else
generate_inspect_method(nclassdef)
end
end
if nat.name == "auto_derive" then
if not nclassdef isa AStdClassdef then
toolcontext.error(nclassdef.location, "Syntax Error: only a concrete class can be `{nat.name}`.")
else
generate_derive_to_map_method(nclassdef, nat)
end
end
end
src/frontend/deriving.nit:36,2--53,4
redef fun process_annotated_node(node, nat)
do
var name = nat.name
if primtives_annotations.has(name) then return
var mmodule = self.mmodule
if mmodule == null then return
# Lazily build the full user-list
var annots = user_annotations.get_or_null(mmodule)
if annots == null then
annots = new HashSet[String]
annots.add_all(declared_annotations.lookup_joined_values(mmodule, private_visibility))
user_annotations[mmodule] = annots
end
#nat.debug "for {mmodule}: {annots.join(" ")}"
if annots.has(name) then return
toolcontext.modelbuilder.warning(nat, "unknown-annotation", "Warning: unknown annotation `{name}`.")
annots.add(name) # to avoid multiple errors on the same name
end
src/frontend/check_annotation.nit:126,2--148,4
redef fun process_annotated_node(nstring, nat)
do
var annot_name = nat.n_atid.n_id.text
var is_vertex = annot_name == annot_name_vertex
var is_fragment = annot_name == annot_name_fragment
# Skip if we are not interested
if not is_vertex and not is_fragment then return
# Only applicable on strings
if not nstring isa AStringFormExpr then
toolcontext.error(nstring.location,
"Syntax Error: only a string literal can be annotated as `{annot_name}`.")
return
end
# Do not double check if tool is in path
var in_path = tool_is_in_path
if in_path == null then
# Is _glslangValidator_ installed?
var proc_which = new ProcessReader("which", "glslangValidator")
proc_which.wait
proc_which.close
var status = proc_which.status
in_path = status == 0
tool_is_in_path = in_path
end
if not in_path then
toolcontext.advice(nat.location, "glslvalidator",
"Warning: program `glslangValidator` not in PATH, cannot validate this shader.")
return
end
# Get the shader source
var shader = nstring.value
# Copy the shader to a file
# TODO make it more portable
var tmp = "/tmp/"
var ext
if is_vertex then
ext = "vert"
else ext = "frag"
var path = tmp / "nit_shader." + ext
shader.write_to_file path
# Execute the validator
var proc_validator = new ProcessReader("glslangValidator", path)
proc_validator.wait
var lines = proc_validator.read_all.split('\n')
proc_validator.close
# Parse errors
var regex = "[A-Z]+: ([0-9]+):([0-9]+): (.*)".to_re
for line in lines do
var match = line.search(regex)
# Does it match an error?
# If not, then it should be the summary
if match != null then
var shader_line_no = match.subs[1].to_s.to_i
var msg = match.subs[2].to_s
var line_start = nstring.location.line_start + shader_line_no
var char_start = 0
var char_end = 0
var loc = new Location(nat.location.file,
line_start, line_start,
char_start, char_end)
toolcontext.warning(loc, "glslvalidator",
"Shader error on {msg}")
end
end
end
src/frontend/glsl_validation.nit:43,2--119,4
redef fun process_annotated_node(nmethdef, nat)
do
if nat.n_atid.n_id.text != "threaded" then return
if not nmethdef isa AMethPropdef then
toolcontext.error(nat.location, "Syntax Error: only a method can be threaded.")
return
end
#TODO: check for self calls
# Get the module associated with this method
var amod = nmethdef.parent.parent
assert amod isa AModule
# Construct the name of the generated class
var classname = "Threaded"
# Try to get the name of the class
if nmethdef.parent isa AStdClassdef then
classname += nmethdef.parent.as(AStdClassdef).n_qid.n_id.text
end
# Try to get the name of the method
if nmethdef.n_methid isa AIdMethid then
classname += nmethdef.n_methid.as(AIdMethid).n_id.text
end
# Handle methods with a return value
var has_rvalue = nmethdef.n_signature.n_type != null
var vtype = ""
if has_rvalue then
vtype = "redef type E: " + nmethdef.n_signature.n_type.n_qid.n_id.text
end
# create a return type
var n_id = new TClassid
n_id.text = classname
var n_qid = new AQclassid
n_qid.n_id = n_id
var n_type = new AType
n_type.n_qid = n_qid
nmethdef.n_signature.n_type = n_type
var params = new Array[String]
for param in nmethdef.n_signature.n_params do
var typ = param.n_type.n_qid.n_id.text
if param.n_type.n_kwnullable != null then typ = "nullable {typ}"
params.add """
var {{{param.n_id.text}}}: {{{typ}}}
"""
end
# String corresponding to the generated class
var classdef_source = """
class {{{classname}}}
super Thread
{{{vtype}}}
{{{params.join("\n")}}}
redef fun main do
end
end
"""
# Parse newly obtained classdef
var classdef = toolcontext.parse_classdef(classdef_source)
assert classdef isa AStdClassdef
# Get the `main` fun of the class
var mainfun: nullable AMethPropdef = null
for prop in classdef.n_propdefs do
if prop isa AMethPropdef then mainfun = prop
end
assert mainfun != null
# Make the statements from `main` fun be the statements from the "threaded" fun
mainfun.n_block = nmethdef.n_block
# Add "return null" to the end of the `main` function
if not has_rvalue then
var s_nullreturn = "return null"
var nullreturn = toolcontext.parse_something(s_nullreturn)
assert nullreturn isa AExpr
mainfun.n_block.as(ABlockExpr).n_expr.add(nullreturn)
end
# Create new body for the annotated fun
var s_newbody : String
if nmethdef.n_signature.n_params.not_empty then
var init_params = new Array[String]
for param in nmethdef.n_signature.n_params do
init_params.add(param.n_id.text)
end
s_newbody ="""
var thread = new {{{classname}}}({{{init_params.join(",")}}})
thread.start
return thread
"""
else
s_newbody = """
var thread = new {{{classname}}}
thread.start
return thread
"""
end
var newbody = toolcontext.parse_something(s_newbody)
nmethdef.n_block = newbody.as(ABlockExpr)
nmethdef.validate
# Add the new class to the module
amod.n_classdefs.add(classdef)
classdef.validate
end
src/frontend/parallelization_phase.nit:34,2--150,4
redef fun process_annotated_node(nmodule, nat) do
if not nat.name == "i18n" then return
if not nmodule isa AModuledecl then
toolcontext.error(nmodule.location, "Error: The localized language can only be used on module declarations.")
return
end
var domain = nmodule.n_name.n_id.text
var lang: nullable String = null
if nat.n_args.length > 0 then
lang = nat.arg_as_string(toolcontext.modelbuilder)
if lang == null then return
end
var module_dir = nmodule.location.file.filename.dirname.realpath
var locale_dir = module_dir / "languages"
if not locale_dir.file_exists then locale_dir.mkdir
var amodule = nmodule.parent.as(AModule)
var vi = new StringFinder(domain, locale_dir, toolcontext, amodule)
vi.enter_visit(amodule)
var module_name = nmodule.location.file.filename.basename(".nit")
var pot_path = locale_dir / module_name
var arr = vi.strings.values.to_a
var po = new POFile(arr)
po.write_template(pot_path)
if lang != null then
for i in po.strings do
i.msgstr = i.msgid
end
var lang_dir = locale_dir / lang
if not lang_dir.file_exists then lang_dir.mkdir
var messages_dir = lang_dir / "LC_MESSAGES"
if not messages_dir.file_exists then messages_dir.mkdir
po.write_to_file(messages_dir / module_name)
end
var lit = new LiteralVisitor(toolcontext)
lit.enter_visit(amodule)
end
src/frontend/i18n_phase.nit:31,2--80,4
redef fun process_annotated_node(nclass, nat)
do
if nat.n_atid.n_id.text != "actor" then return
if not nclass isa AStdClassdef then
toolcontext.error(nat.location, "Syntax Error: only a class can be annotated as an actor.")
return
end
end
src/frontend/actors_generation_phase.nit:221,2--229,4
redef fun process_annotated_node(node, nat)
do
# Skip if we are not interested
var text = nat.n_atid.n_id.text
if text != "restful" then return
if not node isa AMethPropdef then
toolcontext.error(nat.location,
"Syntax Error: `restful` can only be applied on method definitions")
return
end
var mpropdef = node.mpropdef
if mpropdef == null then return
var mproperty = mpropdef.mproperty
var mclassdef = mpropdef.mclassdef
var mmodule = mclassdef.mmodule
var http_resources = new Array[String]
var http_methods = new Array[String]
for arg in nat.n_args do
var str = arg.as_string
var id = arg.collect_text
if str != null then
# String -> rename resource
http_resources.add str
else if arg isa ATypeExpr and not id.chars.has("[") then
# Class id -> HTTP method
http_methods.add id
else if id == "async" then
mproperty.restful_async = true
else
toolcontext.error(nat.location,
"Syntax Error: `restful` expects String literals or ids as arguments.")
return
end
end
# Test subclass of `RestfulAction`
var sup_class_name = "RestfulAction"
var sup_class = toolcontext.modelbuilder.try_get_mclass_by_name(
nat, mmodule, sup_class_name)
var in_hierarchy = mclassdef.in_hierarchy
if in_hierarchy == null or sup_class == null then return
var sup_classes = in_hierarchy.greaters
if not sup_classes.has(sup_class.intro) then
toolcontext.error(nat.location,
"Syntax Error: `restful` is only valid within subclasses of `{sup_class_name}`")
return
end
# Register the property
mclassdef.restful_methods.add mproperty
restful_classes.add mclassdef
if http_resources.not_empty then mproperty.restful_resources = http_resources
mproperty.restful_verbs = http_methods
end
src/nitrestful.nit:28,2--85,4