#[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)), } }; }