use crate::ast::*;
pub trait Locatable {
fn loc_mut(&mut self) -> &mut Location;
fn loc(self) -> Location;
}
impl Locatable for StackParam {
fn loc_mut(&mut self) -> &mut Location {
&mut self.loc
}
fn loc(self) -> Location {
self.loc
}
}
impl Locatable for Statement {
fn loc_mut(&mut self) -> &mut Location {
match self {
Statement::IfStatement { loc, .. } => loc,
Statement::LocktimeStatement { loc, .. } => loc,
Statement::VerifyStatement(loc, ..) => loc,
Statement::ExpressionStatement(loc, ..) => loc,
}
}
fn loc(self) -> Location {
match self {
Statement::IfStatement { loc, .. } => loc,
Statement::LocktimeStatement { loc, .. } => loc,
Statement::VerifyStatement(loc, ..) => loc,
Statement::ExpressionStatement(loc, ..) => loc,
}
}
}
impl Locatable for Expression {
fn loc_mut(&mut self) -> &mut Location {
match self {
Expression::Variable(loc, ..) => loc,
Expression::NumberLiteral(loc, ..) => loc,
Expression::BooleanLiteral(loc, ..) => loc,
Expression::StringLiteral(loc, ..) => loc,
Expression::LogicalExpression { loc, .. } => loc,
Expression::CompareExpression { loc, .. } => loc,
Expression::UnaryMathExpression { loc, .. } => loc,
Expression::BinaryMathExpression { loc, .. } => loc,
Expression::UnaryCryptoExpression { loc, .. } => loc,
Expression::CheckSigExpression { loc, .. } => loc,
Expression::ByteExpression { loc, .. } => loc,
}
}
fn loc(self) -> Location {
match self {
Expression::Variable(loc, ..) => loc,
Expression::NumberLiteral(loc, ..) => loc,
Expression::BooleanLiteral(loc, ..) => loc,
Expression::StringLiteral(loc, ..) => loc,
Expression::LogicalExpression { loc, .. } => loc,
Expression::CompareExpression { loc, .. } => loc,
Expression::UnaryMathExpression { loc, .. } => loc,
Expression::BinaryMathExpression { loc, .. } => loc,
Expression::UnaryCryptoExpression { loc, .. } => loc,
Expression::CheckSigExpression { loc, .. } => loc,
Expression::ByteExpression { loc, .. } => loc,
}
}
}
impl Locatable for Factor {
fn loc_mut(&mut self) -> &mut Location {
match self {
Factor::SingleSigFactor { loc, .. } => loc,
Factor::MultiSigFactor { loc, .. } => loc,
}
}
fn loc(self) -> Location {
match self {
Factor::SingleSigFactor { loc, .. } => loc,
Factor::MultiSigFactor { loc, .. } => loc,
}
}
}
pub fn build_line_index(source: &str) -> Vec<usize> {
std::iter::once(0)
.chain(source.match_indices('\n').map(|(i, _)| i + 1))
.collect()
}
pub fn get_line_and_column(line_index: &[usize], byte_offset: usize) -> (usize, usize) {
let line = line_index
.iter()
.rposition(|&start| start <= byte_offset)
.map_or(1, |i| i + 1);
let column = byte_offset - line_index[line - 1] + 1;
(line, column)
}
pub fn set_stack_location(stack_vec: &mut Vec<Vec<StackParam>>, line_index: &[usize]) {
for stack in stack_vec {
for item in stack {
let loc = item.loc_mut();
let (line, column) = get_line_and_column(line_index, loc.start);
loc.line = line;
loc.column = column;
}
}
}
pub fn set_ast_location(ast: &mut Vec<Statement>, line_index: &[usize]) {
for stmt in ast {
set_stmt_location(stmt, line_index);
}
}
pub fn set_stmt_location(stmt: &mut Statement, line_index: &[usize]) {
let loc = stmt.loc_mut();
let (line, column) = get_line_and_column(line_index, loc.start);
loc.line = line;
loc.column = column;
match stmt {
Statement::VerifyStatement(_loc, expr) => {
set_expr_location(expr, line_index);
}
Statement::ExpressionStatement(_loc, expr) => {
set_expr_location(expr, line_index);
}
Statement::IfStatement {
loc: _,
condition_expr: expr,
if_block,
else_block,
} => {
set_expr_location(expr, line_index);
for if_stmt in if_block {
set_stmt_location(if_stmt, line_index);
}
if let Some(else_b) = else_block.as_mut() {
for else_stmt in else_b {
set_stmt_location(else_stmt, line_index);
}
}
}
_ => (),
}
}
pub fn set_expr_location(expr: &mut Expression, line_index: &[usize]) {
let loc = expr.loc_mut();
let (line, column) = get_line_and_column(line_index, loc.start);
loc.line = line;
loc.column = column;
match expr {
Expression::CheckSigExpression {
loc: _,
operand,
op: _,
} => {
set_factor_location(&mut *operand, line_index);
}
Expression::UnaryCryptoExpression {
loc: _,
operand,
op,
} => set_expr_location(operand, line_index),
Expression::LogicalExpression {
loc: _,
lhs,
op,
rhs,
} => {
set_expr_location(lhs, line_index);
set_expr_location(rhs, line_index);
}
Expression::CompareExpression {
loc: _,
lhs,
op,
rhs,
} => {
set_expr_location(lhs, line_index);
set_expr_location(rhs, line_index);
}
Expression::UnaryMathExpression {
loc: _,
operand,
op,
} => set_expr_location(operand, line_index),
Expression::BinaryMathExpression {
loc: _,
lhs,
op,
rhs,
} => {
set_expr_location(lhs, line_index);
set_expr_location(rhs, line_index);
}
Expression::ByteExpression {
loc: _,
operand,
op: _,
} => set_expr_location(operand, line_index),
_ => (),
}
}
pub fn set_factor_location(factor: &mut Factor, line_index: &[usize]) {
let loc = factor.loc_mut();
let (line, column) = get_line_and_column(line_index, loc.start);
loc.line = line;
loc.column = column;
match factor {
Factor::SingleSigFactor {
loc: _,
sig,
pubkey,
} => {
set_expr_location(sig, line_index);
set_expr_location(pubkey, line_index);
}
Factor::MultiSigFactor { loc: _, m: _, n } => {
for factor in n {
match factor {
Factor::SingleSigFactor {
loc: _,
sig,
pubkey,
} => {
set_expr_location(sig, line_index);
set_expr_location(pubkey, line_index);
}
_ => continue,
}
}
}
}
}
use lazy_static::lazy_static;
use regex::Regex;
pub fn strip_comments(source: &str) -> String {
lazy_static! {
static ref COMMENT_REGEX: Regex = Regex::new(r"(//[^\n\r]*)|(/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)").unwrap();
}
COMMENT_REGEX.replace_all(source, "").to_string()
}