<commit_before># 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.

# Management and utilities on annotations
module annotation

import modelbuilder
private import literal
import model::mmodule_data

redef class Prod
	super ANode

	# Try to get its single annotation with a given name
	# If there is no such an annotation, null is returned.
	# If there is more than one annotation, a error message is printed and the first annotation is returned
	fun get_single_annotation(name: String, modelbuilder: ModelBuilder): nullable AAnnotation
	do
		var res = get_annotations(name)
		if res.is_empty then return null
		if res.length > 1 then
			modelbuilder.error(res[1], "Error: multiple annotation `{name}`. A previous one is defined line {res[0].location.line_start}")
		end
		return res.first
	end

	# Return all its annotations of a given name in the order of their declaration
	# Retun an empty array if no such an annotation.
	fun get_annotations(name: String): Array[AAnnotation]
	do
		var res = new Array[AAnnotation]
		var nas = n_annotations
		if nas == null then return res
		for na in nas.n_items do
			if na.name != name then continue
			res.add(na)
		end
		return res
	end
end

redef class AAnnotation
	# The name of the annotation
	fun name: String
	do
		return n_atid.n_id.text
	end

	# Get the single argument of `self` as a `String`.
	# Raise error and return null on any inconsistency.
	fun arg_as_string(modelbuilder: ModelBuilder): nullable String
	do
		var args = n_args
		if args.length == 1 then
			var arg = args.first.as_string
			if arg != null then return arg
		end

		modelbuilder.error(self, "Annotation error: \"{name}\" expects a single String as argument.")
		return null
	end

	# Get the single argument of `self` as an `Int`.
	# Raise error and return null on any inconsistency.
	fun arg_as_int(modelbuilder: ModelBuilder): nullable Int
	do
		var args = n_args
		if args.length == 1 then
			var arg = args.first.as_int
			if arg != null then return arg
		end

		modelbuilder.error(self, "Annotation error: \"{name}\" expects a single Int as argument.")
		return null
	end

	# Get the single argument of `self` as an identifier.
	# Raise error and return null on any inconsistency.
	fun arg_as_id(modelbuilder: ModelBuilder): nullable String
	do
		var args = n_args
		if args.length == 1 then
			var arg = args.first.as_id
			if arg != null then return arg
		end

		modelbuilder.error(self, "Annotation error: \"{name}\" expects a single identifier as argument.")
		return null
	end
end

redef class AExpr
	# Get `self` as a `String`.
	# Return null if not a string.
	fun as_string: nullable String
	do
		if not self isa AStringFormExpr then return null
		return self.value.as(not null)
	end

	# Get `self` as an `Int`.
	# Return null if not an integer.
	fun as_int: nullable Int
	do
		if not self isa AIntExpr then return null
		return self.value.as(not null)
	end

	# Get `self` as a single identifier.
	# Return null if not a single identifier.
	fun as_id: nullable String
	do
		if not self isa ACallExpr then return null<commit_msg>annotation: `as_id` works with operators and setters<commit_after># 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.

# Management and utilities on annotations
module annotation

import modelbuilder
private import literal
import model::mmodule_data

redef class Prod
	super ANode

	# Try to get its single annotation with a given name
	# If there is no such an annotation, null is returned.
	# If there is more than one annotation, a error message is printed and the first annotation is returned
	fun get_single_annotation(name: String, modelbuilder: ModelBuilder): nullable AAnnotation
	do
		var res = get_annotations(name)
		if res.is_empty then return null
		if res.length > 1 then
			modelbuilder.error(res[1], "Error: multiple annotation `{name}`. A previous one is defined line {res[0].location.line_start}")
		end
		return res.first
	end

	# Return all its annotations of a given name in the order of their declaration
	# Retun an empty array if no such an annotation.
	fun get_annotations(name: String): Array[AAnnotation]
	do
		var res = new Array[AAnnotation]
		var nas = n_annotations
		if nas == null then return res
		for na in nas.n_items do
			if na.name != name then continue
			res.add(na)
		end
		return res
	end
end

redef class AAnnotation
	# The name of the annotation
	fun name: String
	do
		return n_atid.n_id.text
	end

	# Get the single argument of `self` as a `String`.
	# Raise error and return null on any inconsistency.
	fun arg_as_string(modelbuilder: ModelBuilder): nullable String
	do
		var args = n_args
		if args.length == 1 then
			var arg = args.first.as_string
			if arg != null then return arg
		end

		modelbuilder.error(self, "Annotation error: \"{name}\" expects a single String as argument.")
		return null
	end

	# Get the single argument of `self` as an `Int`.
	# Raise error and return null on any inconsistency.
	fun arg_as_int(modelbuilder: ModelBuilder): nullable Int
	do
		var args = n_args
		if args.length == 1 then
			var arg = args.first.as_int
			if arg != null then return arg
		end

		modelbuilder.error(self, "Annotation error: \"{name}\" expects a single Int as argument.")
		return null
	end

	# Get the single argument of `self` as an identifier.
	# Raise error and return null on any inconsistency.
	fun arg_as_id(modelbuilder: ModelBuilder): nullable String
	do
		var args = n_args
		if args.length == 1 then
			var arg = args.first.as_id
			if arg != null then return arg
		end

		modelbuilder.error(self, "Annotation error: \"{name}\" expects a single identifier as argument.")
		return null
	end
end

redef class AExpr
	# Get `self` as a `String`.
	# Return null if not a string.
	fun as_string: nullable String
	do
		if not self isa AStringFormExpr then return null
		return self.value.as(not null)
	end

	# Get `self` as an `Int`.
	# Return null if not an integer.
	fun as_int: nullable Int
	do
		if not self isa AIntExpr then return null
		return self.value.as(not null)
	end

	# Get `self` as a single identifier.
	# Return null if not a single identifier.
	fun as_id: nullable String
	do
		if self isa AMethidExpr then
			return self.collect_text
		end
		if not self isa ACallExpr then return null
{'fraction_non_alphanumeric': 0.06922867266285092, 'fraction_numerical': 0.002725538293813028, 'mean_word_length': 3.7014734144778987, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6111623', 'n_tokens_mistral': 2335, 'n_tokens_neox': 2170, 'n_words': 1005}