#[macro_export]
macro_rules! token {
($self:expr, $token:expr) => {
$crate::lexer::Token {
token_type: $token,
start_column: $self.start,
end_column: $self.line_current,
line: $self.line,
}
};
}
#[macro_export]
macro_rules! token_display {
( $match_to:expr, $f:expr, $( $name:tt),*) => {
match $match_to {
$( $name => { $f.write_str(stringify!($name))?; } ),*
_ => ()
}
}
}
#[macro_export]
macro_rules! ast {
( $ast:ident { $field:ident: $ast_type:ty $( , $extra_field:ident: $extra_type:ty )* } ) => {
#[derive(::std::fmt::Debug, ::std::clone::Clone)]
pub struct $ast {
pub $field: $ast_type,
pub start_line: usize,
pub end_line: usize,
pub start_column: usize,
pub end_column: usize,
$( pub $extra_field: $extra_type ),*
}
}
}
#[macro_export]
macro_rules! lit {
($type:ident, $data:expr, $token:expr) => {
$crate::parser::AST {
kind: $crate::parser::ASTType::Lit($crate::parser::Lit::$type($data)),
extensions: Vec::new(),
start_line: $token.line,
end_line: $token.line,
start_column: $token.start_column,
end_column: $token.end_column,
}
};
}
#[macro_export]
macro_rules! ast_from_token {
($ast:tt, $kind:expr, $start:expr, $end:expr) => {
$ast {
kind: $kind,
extensions: Vec::new(),
start_line: $start.line,
end_line: $end.line,
start_column: $start.start_column,
end_column: $end.end_column,
}
};
}
#[macro_export]
macro_rules! ast_from_token_ast {
($ast:tt, $kind:expr, $start:expr, $end:expr) => {
$ast {
kind: $kind,
extensions: Vec::new(),
start_line: $start.line,
end_line: $end.end_line,
start_column: $start.start_column,
end_column: $end.end_column,
}
};
}
#[macro_export]
macro_rules! ast_from_ast {
($ast:tt, $kind:expr, $start:expr, $end:expr) => {
$ast {
kind: $kind,
extensions: Vec::new(),
start_line: $start.start_line,
end_line: $end.end_line,
start_column: $start.start_column,
end_column: $end.end_column,
}
};
}
#[macro_export]
macro_rules! ast_from_ast_token {
($ast:tt, $kind:expr, $start:expr, $end:expr) => {
$ast {
kind: $kind,
extensions: Vec::new(),
start_line: $start.start_line,
end_line: $end.line,
start_column: $start.start_column,
end_column: $end.end_column,
}
};
}
#[macro_export]
macro_rules! name {
($name:expr, $token:expr) => {
$crate::ast::Name {
name: $name,
start_column: $token.start_column,
end_column: $token.end_column,
line: $token.line,
}
};
}
#[macro_export]
macro_rules! push_output {
( $match_to:expr, $output:expr, $( $name:tt ),*) => {
match $match_to {
$( $name => { $output += stringify!($name); } ),*
}
}
}
#[macro_export]
macro_rules! unexpected_token {
($self:expr, $message:expr, $token:expr, $hint:expr) => {
$crate::error::KabelError::new(
$crate::error::ErrorKind::UnexpectedToken,
format!(
$message,
$self.text[$token.line][$token.start_column..$token.end_column].to_string()
),
Some($hint),
$token.line,
$token.start_column,
$self.text[$token.line].to_string(),
)
};
($self:expr, $message:expr, $token:expr) => {
$crate::error::KabelError::new(
$crate::error::ErrorKind::UnexpectedToken,
format!(
$message,
$self.text[$token.line][$token.start_column..$token.end_column].to_string()
),
None,
$token.line,
$token.start_column,
$self.text[$token.line].to_string(),
)
};
}
#[macro_export]
macro_rules! ast_error {
($self:expr, $type:expr, $expr:expr, $message:expr $(, $message_fmt:expr )* ; $hint:expr $(, $hint_fmt:expr )* ) => {
$crate::error::KabelError::new(
$type,
format!($message, $( $message_fmt ),* ),
Some(format!($hint, $( $hint_fmt ),*)),
$expr.start_line,
$expr.start_column,
$crate::collect_lines!($self.text[$expr.start_line..$expr.end_line+1]),
)
};
($self:expr, $type:expr, $expr:expr, $message:expr $(, $message_fmt:expr )*) => {
$crate::error::KabelError::new(
$type,
format!($message, $( $message_fmt ),* ),
None,
$expr.start_line,
$expr.start_column,
$crate::collect_lines!($self.text[$expr.start_line..$expr.end_line+1]),
)
};
}
/*#[macro_export]
macro_rules! out_of_scope {
($self:expr, $message:expr, $name:expr, $expr:expr, $hint:expr) => {
$crate::error::KabelError::new(
$crate::error::ErrorKind::OutOfScope,
format!($message, $name),
$expr.start_line,
$expr.start_column,
$crate::collect_lines!($self.text[$expr.start_line..$expr.end_line+1]),
)
};
}*/
#[macro_export]
macro_rules! out_of_scope_var {
($self:expr, $type:expr, $expr:expr, $message:expr, $name:expr ; $hint:expr $(, $hint_fmt:expr )* ) => {
$crate::error::KabelError::new(
$type,
format!($message, $name.name),
Some(format!($hint, $( $hint_fmt ),*)),
$expr.start_line,
$expr.start_column,
$crate::collect_lines!($self.text[$expr.start_line..$expr.end_line+1]),
)
};
($self:expr, $type:expr, $expr:expr, $message:expr, $name:expr) => {
$crate::error::KabelError::new(
$type,
format!($message, $name),
None,
$expr.start_line,
$expr.start_column,
$crate::collect_lines!($self.text[$expr.start_line..$expr.end_line+1]),
)
};
}
#[macro_export]
macro_rules! vm_error {
($self:expr, $type:expr, $message:expr $(, $message_fmt:expr )* ; $hint:expr $(, $hint_fmt:expr )* ) => {
{
let line = $self.find_line();
$crate::runtime_error::KabelRuntimeError::new(
$type,
format!($message, $( $message_fmt ),* ),
Some(format!(hint, $( $hint_fmt ),*)),
line,
$self.text[line].to_string(),
)
}
};
($self:expr, $type:expr, $message:expr $(, $message_fmt:expr )*) => {
{
let line = $self.find_line();
$crate::runtime_error::KabelRuntimeError::new(
$type,
format!($message, $( $message_fmt ),* ),
None,
line,
$self.text[line].to_string(),
)
}
};
}
/*#[macro_export]
macro_rules! mismatched_types {
($self:expr, $message:expr, $( $args:expr ),*) => {
{
let line = $self.find_line();
$crate::runtime_error::KabelRuntimeError::new(
$crate::runtime_error::RuntimeErrorKind::MismatchedTypes,
format!($message, $( $args ),*),
line,
$self.text[line].to_string(),
)
}
};
}
#[macro_export]
macro_rules! wrong_type {
($self:expr, $message:expr $(, $args:expr )*) => {
{
let line = $self.find_line();
$crate::runtime_error::KabelRuntimeError::new(
$crate::runtime_error::RuntimeErrorKind::WrongType,
format!($message, $( $args ),*),
line,
$self.text[line].to_string(),
)
}
};
}*/
#[macro_export]
macro_rules! collect_lines {
($string:expr) => {
$string
.iter()
.fold("".to_string(), |acc, string| acc + string + "\n")
.trim_end()
.to_string()
};
}
#[macro_export]
macro_rules! codegen_binary {
($self:expr, $left:expr, $right:expr, $match_to:expr, $( $oper:tt, $code:tt ),*) => {
match $match_to {
$( $oper => {
$self.visit($right);
$self.visit($left);
$self.vm.units[$self.vm.unit_ptr].code.push(OpCode::$code.into());
$self.vm.units[$self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1;
} )*
}
};
}
#[macro_export]
macro_rules! codegen_unary {
($self:expr, $right:expr, $match_to:expr, $( $oper:tt, $code:tt ),*) => {
match $match_to {
$( $oper => {
$self.visit($right);
$self.vm.units[$self.vm.unit_ptr].code.push(OpCode::$code.into());
$self.vm.units[$self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1;
} )*
}
};
}
#[macro_export]
macro_rules! push_codegen {
($match_to:expr, $vm:expr, $output:expr, $( $code:tt ), *) => {
match $match_to {
$( $code => {
$output += &$vm.ip.to_string();
$output += " ";
$output += &$vm.find_line().to_string();
$output += " ";
$output += stringify!($code);
$output += "\n";
} )*
_ => {}
}
};
}
#[macro_export]
macro_rules! vm_boolean_equality {
($self:expr, $oper:tt) => {
match ($self.stack.pop().expect(&("Couldn't pop left side of ".to_owned() + stringify!($oper))),
$self.stack.pop().expect(&("Couldn't pop right side of ".to_owned() + stringify!($oper)))) {
(Num(v1), Num(v2)) => $self.stack.push(Bool(v1 $oper v2)),
(Str(v1), Str(v2)) => $self.stack.push(Bool(v1 $oper v2)),
(Bool(v1), Bool(v2)) => $self.stack.push(Bool(v1 $oper v2)),
(Null, Null) => $self.stack.push(Bool(true)),
(_v1, _v2) => $self.stack.push(Bool(false)),
}
};
}
#[macro_export]
macro_rules! vm_boolean_comparison {
($self:expr, $oper:tt) => {
match ($self.stack.pop().expect(&("Couldn't pop left side of ".to_owned() + stringify!($oper))),
$self.stack.pop().expect(&("Couldn't pop right side of ".to_owned() + stringify!($oper)))) {
(Num(v1), Num(v2)) => $self.stack.push(Bool(v1 $oper v2)),
(Str(v1), Str(v2)) => $self.stack.push(Bool(v1 $oper v2)),
(Bool(v1), Bool(v2)) => $self.stack.push(Bool(v1 $oper v2)),
(Null, _) => return Err(vm_error!($self, RuntimeErrorKind::WrongType, "Tried to perform comparison \"{}\" on value null", stringify!($tt))),
(_, Null) => return Err(vm_error!($self, RuntimeErrorKind::WrongType, "Tried to perform comparison \"{}\" on value null", stringify!($tt))),
(_v1, _v2) => $self.stack.push(Bool(false)),
}
};
}