1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
use anyhow::{anyhow, Result};
use format_buf::format;
use num_bigint::BigInt;
use num_traits::ToPrimitive;

use std::any::{type_name, Any};
use std::fmt::Debug;

use super::Type;

mod bool;
mod char;
mod int;
mod option;
mod string;
mod vec;

mod chrono;
mod semver;

mod build_info;
mod compiler_channel;
mod compiler_info;
mod crate_info;
mod git_info;
mod version_control;

mod functions;
pub(crate) use functions::call_function;

mod macros;
pub(crate) use macros::call_macro;

pub(crate) trait Value: Debug {
	fn call_base(&self, func: &str, args: &[Box<dyn Value>]) -> Result<Box<dyn Value>> {
		match func {
			OP_FIELD_ACCESS => {
				let field = as_field_name(args);
				Err(anyhow!(
					"The field {} does not exist for objects of type {}",
					field,
					self.get_type()
				))
			}
			OP_TUPLE_INDEX => Err(anyhow!("Type {} cannot be tuple-indexed", self.get_type())),
			OP_ARRAY_INDEX => Err(anyhow!("Type {} cannot be indexed", self.get_type())),
			_ => Err(anyhow!(
				"Function {} cannot be called with arguments {:#?} on objects of type {}",
				func,
				args,
				self.get_type()
			)),
		}
	}

	fn call(&self, func: &str, args: &[Box<dyn Value>]) -> Result<Box<dyn Value>> {
		self.call_base(func, args)
	}

	fn get_type(&self) -> Type;

	fn as_any(&self) -> &dyn Any;

	fn format(&self, buffer: &mut String, spec: FormatSpecifier);
}

#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub(crate) enum FormatSpecifier {
	Default,
	Debug,
	DebugAlt,
}

pub(crate) const OP_FIELD_ACCESS: &str = "!field";
pub(crate) const OP_TUPLE_INDEX: &str = "!tuple_index";
pub(crate) const OP_ARRAY_INDEX: &str = "!array_index";

fn as_field_name(args: &[Box<dyn Value>]) -> &str {
	assert!(
		args.len() == 1,
		"Accessing a field must have exactly one operand (the field name)"
	);

	args[0]
		.as_any()
		.downcast_ref::<String>()
		.expect("The field name must be a string when accessing a field.")
}

fn as_index(args: &[Box<dyn Value>]) -> usize {
	assert!(
		args.len() == 1,
		"Accessing a field must have exactly one operand (the field name)"
	);

	args[0]
		.as_any()
		.downcast_ref::<BigInt>()
		.expect("The array index must be an integer.")
		.to_usize()
		.expect("The array index does not fit into the type usize.")
}

fn as_arguments_0(args: &[Box<dyn Value>]) -> Result<()> {
	if args.is_empty() {
		Ok(())
	} else {
		Err(anyhow!("Wrong number of arguments (should be 0)"))
	}
}

fn as_arguments_1<'a, T1: 'static>(args: &'a [Box<dyn Value>]) -> Result<(&'a T1,)> {
	if args.len() != 1 {
		return Err(anyhow!("Wrong number of arguments (should be 1)"));
	}

	Ok((args[0]
		.as_any()
		.downcast_ref::<T1>()
		.ok_or_else(|| anyhow!("Argument #1 should have type {}", type_name::<T1>()))?,))
}

#[allow(dead_code)]
fn as_arguments_2<'a, T1: 'static, T2: 'static>(args: &'a [Box<dyn Value>]) -> Result<(&'a T1, &'a T2)> {
	if args.len() != 2 {
		return Err(anyhow!("Wrong number of arguments (should be 1)"));
	}

	Ok((
		args[0]
			.as_any()
			.downcast_ref::<T1>()
			.ok_or_else(|| anyhow!("Argument #1 should have type {}", type_name::<T1>()))?,
		args[1]
			.as_any()
			.downcast_ref::<T2>()
			.ok_or_else(|| anyhow!("Argument #2 should have type {}", type_name::<T1>()))?,
	))
}