use super::functions::*;
use crate::error_impl::ParseError;
use crate::tokens::{Span, Token, TokenKind};
use std::collections::HashMap;
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MacroVarExt {
pub name: String,
pub is_rep: bool,
}
impl MacroVarExt {
#[allow(dead_code)]
pub fn simple(name: &str) -> Self {
MacroVarExt {
name: name.to_string(),
is_rep: false,
}
}
#[allow(dead_code)]
pub fn rep(name: &str) -> Self {
MacroVarExt {
name: name.to_string(),
is_rep: true,
}
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub struct MacroLibrary {
pub groups: std::collections::HashMap<String, Vec<MacroDefinitionExt>>,
}
impl MacroLibrary {
#[allow(dead_code)]
pub fn new() -> Self {
MacroLibrary {
groups: std::collections::HashMap::new(),
}
}
#[allow(dead_code)]
pub fn add_to_group(&mut self, group: &str, def: MacroDefinitionExt) {
self.groups.entry(group.to_string()).or_default().push(def);
}
#[allow(dead_code)]
pub fn group(&self, name: &str) -> &[MacroDefinitionExt] {
self.groups.get(name).map(|v| v.as_slice()).unwrap_or(&[])
}
#[allow(dead_code)]
pub fn total_macros(&self) -> usize {
self.groups.values().map(|v| v.len()).sum()
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum SyntaxItem {
Token(TokenKind),
Category(String),
Optional(Box<SyntaxItem>),
Many(Box<SyntaxItem>),
Group(Vec<SyntaxItem>),
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct MacroSubst {
pub var: String,
pub value: String,
}
impl MacroSubst {
#[allow(dead_code)]
pub fn new(var: &str, value: &str) -> Self {
MacroSubst {
var: var.to_string(),
value: value.to_string(),
}
}
}
#[derive(Debug, Clone)]
pub struct MacroDef {
pub name: String,
pub rules: Vec<MacroRule>,
pub doc: Option<String>,
pub hygiene: HygieneInfo,
}
impl MacroDef {
pub fn new(name: String, rules: Vec<MacroRule>, hygiene: HygieneInfo) -> Self {
Self {
name,
rules,
doc: None,
hygiene,
}
}
pub fn with_doc(mut self, doc: String) -> Self {
self.doc = Some(doc);
self
}
pub fn rule_count(&self) -> usize {
self.rules.len()
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub enum MacroExpansionResult {
Ok(String),
Err(MacroExpansionError),
}
impl MacroExpansionResult {
#[allow(dead_code)]
pub fn is_ok(&self) -> bool {
matches!(self, MacroExpansionResult::Ok(_))
}
#[allow(dead_code)]
pub fn unwrap(self) -> String {
match self {
MacroExpansionResult::Ok(s) => s,
MacroExpansionResult::Err(e) => {
panic!("macro expansion error: {}", e.message)
}
}
}
#[allow(dead_code)]
pub fn unwrap_or(self, default: &str) -> String {
match self {
MacroExpansionResult::Ok(s) => s,
MacroExpansionResult::Err(_) => default.to_string(),
}
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub struct MacroMatcher {
pub pattern: Vec<MacroVarExt>,
}
impl MacroMatcher {
#[allow(dead_code)]
#[allow(clippy::should_implement_trait)]
pub fn from_str(s: &str) -> Self {
MacroMatcher {
pattern: s
.split_whitespace()
.map(|tok| {
if let Some(name) = tok.strip_prefix('$') {
MacroVarExt::simple(name)
} else {
MacroVarExt {
name: format!("__lit_{}", tok),
is_rep: false,
}
}
})
.collect(),
}
}
#[allow(dead_code)]
pub fn hole_count(&self) -> usize {
self.pattern
.iter()
.filter(|v| !v.name.starts_with("__lit_"))
.count()
}
#[allow(dead_code)]
pub fn literal_count(&self) -> usize {
self.pattern
.iter()
.filter(|v| v.name.starts_with("__lit_"))
.count()
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct MacroExpansionErrorExt2 {
pub message: String,
pub macro_name: String,
pub depth: usize,
}
impl MacroExpansionErrorExt2 {
#[allow(dead_code)]
pub fn new(macro_name: &str, message: &str, depth: usize) -> Self {
MacroExpansionErrorExt2 {
message: message.to_string(),
macro_name: macro_name.to_string(),
depth,
}
}
#[allow(dead_code)]
pub fn format(&self) -> String {
format!(
"macro '{}' at depth {}: {}",
self.macro_name, self.depth, self.message
)
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Default)]
pub struct MacroExpansionTraceExt {
pub steps: Vec<String>,
}
impl MacroExpansionTraceExt {
#[allow(dead_code)]
pub fn new() -> Self {
MacroExpansionTraceExt { steps: Vec::new() }
}
#[allow(dead_code)]
pub fn record(&mut self, step: &str) {
self.steps.push(step.to_string());
}
#[allow(dead_code)]
pub fn format(&self) -> String {
self.steps
.iter()
.enumerate()
.map(|(i, s)| format!("{}: {}", i, s))
.collect::<Vec<_>>()
.join("\n")
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct MacroExpansionError {
pub macro_name: String,
pub message: String,
pub depth: usize,
}
impl MacroExpansionError {
#[allow(dead_code)]
pub fn new(macro_name: &str, message: &str, depth: usize) -> Self {
MacroExpansionError {
macro_name: macro_name.to_string(),
message: message.to_string(),
depth,
}
}
#[allow(dead_code)]
pub fn format(&self) -> String {
format!(
"macro error in '{}' at depth {}: {}",
self.macro_name, self.depth, self.message
)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MacroErrorKind {
UnknownMacro,
PatternMismatch,
HygieneViolation,
AmbiguousMatch,
ExpansionError,
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub struct DepthLimitedExpanderExt2 {
pub max_depth: usize,
pub current_depth: usize,
}
impl DepthLimitedExpanderExt2 {
#[allow(dead_code)]
pub fn new(max_depth: usize) -> Self {
DepthLimitedExpanderExt2 {
max_depth,
current_depth: 0,
}
}
#[allow(dead_code)]
pub fn can_expand(&self) -> bool {
self.current_depth < self.max_depth
}
#[allow(dead_code)]
pub fn enter(&mut self) -> bool {
if self.current_depth >= self.max_depth {
return false;
}
self.current_depth += 1;
true
}
#[allow(dead_code)]
pub fn exit(&mut self) {
if self.current_depth > 0 {
self.current_depth -= 1;
}
}
}
pub struct MacroExpander {
macros: HashMap<String, MacroDef>,
next_scope: u64,
syntax_defs: Vec<SyntaxDef>,
pub(super) max_depth: u32,
}
impl MacroExpander {
pub fn new() -> Self {
Self {
macros: HashMap::new(),
next_scope: 1,
syntax_defs: Vec::new(),
max_depth: 128,
}
}
pub fn set_max_depth(&mut self, depth: u32) {
self.max_depth = depth;
}
pub fn fresh_scope(&mut self) -> u64 {
let id = self.next_scope;
self.next_scope += 1;
id
}
pub fn register_macro(&mut self, def: MacroDef) {
self.macros.insert(def.name.clone(), def);
}
pub fn unregister_macro(&mut self, name: &str) -> Option<MacroDef> {
self.macros.remove(name)
}
pub fn has_macro(&self, name: &str) -> bool {
self.macros.contains_key(name)
}
pub fn get_macro(&self, name: &str) -> Option<&MacroDef> {
self.macros.get(name)
}
pub fn macro_count(&self) -> usize {
self.macros.len()
}
pub fn register_syntax(&mut self, def: SyntaxDef) {
self.syntax_defs.push(def);
}
pub fn syntax_defs_for(&self, kind: &SyntaxKind) -> Vec<&SyntaxDef> {
self.syntax_defs
.iter()
.filter(|d| &d.kind == kind)
.collect()
}
#[allow(clippy::result_large_err)]
pub fn expand(&mut self, name: &str, input: &[Token]) -> Result<Vec<Token>, MacroError> {
self.expand_with_depth(name, input, 0)
}
#[allow(clippy::result_large_err)]
fn expand_with_depth(
&mut self,
name: &str,
input: &[Token],
depth: u32,
) -> Result<Vec<Token>, MacroError> {
if depth > self.max_depth {
return Err(MacroError::new(
MacroErrorKind::ExpansionError,
format!(
"maximum macro expansion depth ({}) exceeded for '{}'",
self.max_depth, name
),
));
}
let def = self.macros.get(name).cloned().ok_or_else(|| {
MacroError::new(
MacroErrorKind::UnknownMacro,
format!("macro '{}' is not defined", name),
)
})?;
let mut matches = Vec::new();
for rule in &def.rules {
if let Some(bindings) = try_match_rule(rule, input) {
matches.push((rule.clone(), bindings));
}
}
match matches.len() {
0 => Err(MacroError::new(
MacroErrorKind::PatternMismatch,
format!(
"no rule of macro '{}' matches the input ({} tokens)",
name,
input.len()
),
)),
1 => {
let (rule, bindings) = matches
.into_iter()
.next()
.expect("matches.len() == 1 per match arm");
let binding_slice: Vec<(String, Vec<Token>)> = bindings;
Ok(substitute(&rule.template, &binding_slice))
}
_ => Err(MacroError::new(
MacroErrorKind::AmbiguousMatch,
format!(
"{} rules of macro '{}' match the input",
matches.len(),
name
),
)),
}
}
pub fn macro_names(&self) -> Vec<&str> {
let mut names: Vec<&str> = self.macros.keys().map(|s| s.as_str()).collect();
names.sort();
names
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub enum MacroExpansionResultExt2 {
Success(String),
Error(MacroExpansionErrorExt2),
NoMatch,
}
impl MacroExpansionResultExt2 {
#[allow(dead_code)]
pub fn is_success(&self) -> bool {
matches!(self, MacroExpansionResultExt2::Success(_))
}
#[allow(dead_code)]
pub fn as_str(&self) -> Option<&str> {
if let MacroExpansionResultExt2::Success(s) = self {
Some(s)
} else {
None
}
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub enum MacroTemplateNodeExt {
Literal(String),
Var(MacroVarExt),
Rep {
sep: Option<String>,
body: Vec<MacroTemplateNodeExt>,
},
Group(Vec<MacroTemplateNodeExt>),
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct MacroSignature {
pub name: String,
pub param_count: usize,
}
impl MacroSignature {
#[allow(dead_code)]
pub fn new(name: &str, param_count: usize) -> Self {
MacroSignature {
name: name.to_string(),
param_count,
}
}
#[allow(dead_code)]
pub fn format(&self) -> String {
format!("{}/{}", self.name, self.param_count)
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct MacroDefinitionExt {
pub name: String,
pub params: Vec<String>,
pub template: String,
}
impl MacroDefinitionExt {
#[allow(dead_code)]
pub fn new(name: &str, params: Vec<&str>, template: &str) -> Self {
MacroDefinitionExt {
name: name.to_string(),
params: params.into_iter().map(|s| s.to_string()).collect(),
template: template.to_string(),
}
}
#[allow(dead_code)]
pub fn expand(&self, args: &[&str]) -> String {
if args.len() != self.params.len() {
return format!("(error: wrong arity for {})", self.name);
}
let mut env = std::collections::HashMap::new();
for (p, a) in self.params.iter().zip(args.iter()) {
env.insert(p.clone(), a.to_string());
}
let nodes = parse_simple_template_ext(&self.template);
expand_template_ext(&nodes, &env)
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone, Default)]
pub struct MacroStatsExt2 {
pub attempts: usize,
pub successes: usize,
pub failures: usize,
pub max_depth: usize,
}
impl MacroStatsExt2 {
#[allow(dead_code)]
pub fn record_success(&mut self, depth: usize) {
self.attempts += 1;
self.successes += 1;
if depth > self.max_depth {
self.max_depth = depth;
}
}
#[allow(dead_code)]
pub fn record_failure(&mut self) {
self.attempts += 1;
self.failures += 1;
}
#[allow(dead_code)]
pub fn success_rate(&self) -> f64 {
if self.attempts == 0 {
return 1.0;
}
self.successes as f64 / self.attempts as f64
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum SyntaxKind {
Term,
Command,
Tactic,
Level,
Attr,
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone, Default)]
pub struct HygieneContextExt2 {
pub counter: u32,
pub prefix: String,
}
impl HygieneContextExt2 {
#[allow(dead_code)]
pub fn new(prefix: &str) -> Self {
HygieneContextExt2 {
counter: 0,
prefix: prefix.to_string(),
}
}
#[allow(dead_code)]
pub fn fresh(&mut self) -> String {
let name = format!("{}{}", self.prefix, self.counter);
self.counter += 1;
name
}
#[allow(dead_code)]
pub fn generated_count(&self) -> u32 {
self.counter
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum MacroToken {
Literal(TokenKind),
Var(String),
Repeat(Vec<MacroToken>),
Optional(Vec<MacroToken>),
Quote(Vec<MacroToken>),
Antiquote(String),
SpliceArray(String),
}
#[derive(Debug, Clone)]
pub struct MacroRule {
pub pattern: Vec<MacroToken>,
pub template: Vec<MacroToken>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HygieneInfo {
pub scope_id: u64,
pub def_site: Span,
}
impl HygieneInfo {
pub fn new(scope_id: u64, def_site: Span) -> Self {
Self { scope_id, def_site }
}
}
#[derive(Debug, Clone)]
pub struct SyntaxDef {
pub name: String,
pub kind: SyntaxKind,
pub parser: Vec<SyntaxItem>,
}
impl SyntaxDef {
pub fn new(name: String, kind: SyntaxKind, parser: Vec<SyntaxItem>) -> Self {
Self { name, kind, parser }
}
pub fn item_count(&self) -> usize {
self.parser.len()
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Default)]
pub struct MacroStats {
pub expansions: usize,
pub errors: usize,
pub max_depth: usize,
}
impl MacroStats {
#[allow(dead_code)]
pub fn new() -> Self {
MacroStats::default()
}
#[allow(dead_code)]
pub fn record_success(&mut self, depth: usize) {
self.expansions += 1;
if depth > self.max_depth {
self.max_depth = depth;
}
}
#[allow(dead_code)]
pub fn record_error(&mut self) {
self.errors += 1;
}
}
pub struct MacroParser {
tokens: Vec<Token>,
pub(super) pos: usize,
}
impl MacroParser {
pub fn new(tokens: Vec<Token>) -> Self {
Self { tokens, pos: 0 }
}
fn current(&self) -> &Token {
self.tokens
.get(self.pos)
.unwrap_or(&self.tokens[self.tokens.len() - 1])
}
fn is_eof(&self) -> bool {
matches!(self.current().kind, TokenKind::Eof)
}
fn advance(&mut self) -> Token {
let tok = self.current().clone();
if !self.is_eof() {
self.pos += 1;
}
tok
}
pub fn parse_rule(&mut self) -> Result<MacroRule, ParseError> {
let pattern = self.parse_macro_tokens()?;
if !matches!(self.current().kind, TokenKind::Arrow) {
return Err(ParseError::unexpected(
vec!["=>".to_string()],
self.current().kind.clone(),
self.current().span.clone(),
));
}
self.advance();
let template = self.parse_macro_tokens()?;
Ok(MacroRule { pattern, template })
}
pub fn parse_rules(&mut self) -> Result<Vec<MacroRule>, ParseError> {
let mut rules = Vec::new();
rules.push(self.parse_rule()?);
while !self.is_eof() && matches!(self.current().kind, TokenKind::Bar) {
self.advance();
rules.push(self.parse_rule()?);
}
Ok(rules)
}
fn parse_macro_tokens(&mut self) -> Result<Vec<MacroToken>, ParseError> {
let mut tokens = Vec::new();
while !self.is_eof() && !self.is_delimiter() {
tokens.push(self.parse_macro_token()?);
}
Ok(tokens)
}
pub(super) fn parse_macro_token(&mut self) -> Result<MacroToken, ParseError> {
let tok = self.current();
match &tok.kind {
TokenKind::Ident(name) if name.starts_with("$[") && name.ends_with("]*") => {
let inner = name[2..name.len() - 2].to_string();
self.advance();
Ok(MacroToken::SpliceArray(inner))
}
TokenKind::Ident(name) if name.starts_with('$') => {
let var_name = name[1..].to_string();
self.advance();
if var_name.is_empty() && matches!(self.current().kind, TokenKind::LParen) {
self.advance();
let inner = self.parse_group_tokens()?;
if matches!(self.current().kind, TokenKind::RParen) {
self.advance();
}
return match &self.current().kind {
TokenKind::Star => {
self.advance();
Ok(MacroToken::Repeat(inner))
}
TokenKind::Question => {
self.advance();
Ok(MacroToken::Optional(inner))
}
_ => Ok(MacroToken::Repeat(inner)),
};
}
if !var_name.is_empty()
&& !self.is_eof()
&& matches!(self.current().kind, TokenKind::LBracket)
&& self.pos + 2 < self.tokens.len()
&& matches!(self.tokens[self.pos + 1].kind, TokenKind::RBracket)
&& matches!(self.tokens[self.pos + 2].kind, TokenKind::Star)
{
self.advance();
self.advance();
self.advance();
return Ok(MacroToken::SpliceArray(var_name));
}
Ok(MacroToken::Var(var_name))
}
TokenKind::Ident(name) if name == "`" => {
self.advance();
if matches!(self.current().kind, TokenKind::LParen) {
self.advance();
let inner = self.parse_quoted_tokens()?;
if matches!(self.current().kind, TokenKind::RParen) {
self.advance();
}
Ok(MacroToken::Quote(inner))
} else {
Ok(MacroToken::Literal(TokenKind::Ident("`".to_string())))
}
}
TokenKind::Star => {
let kind = tok.kind.clone();
self.advance();
Ok(MacroToken::Literal(kind))
}
TokenKind::LParen => {
let kind = tok.kind.clone();
self.advance();
Ok(MacroToken::Literal(kind))
}
_ => {
let kind = tok.kind.clone();
self.advance();
Ok(MacroToken::Literal(kind))
}
}
}
fn parse_group_tokens(&mut self) -> Result<Vec<MacroToken>, ParseError> {
let mut tokens = Vec::new();
let mut depth = 1u32;
while !self.is_eof() {
match &self.current().kind {
TokenKind::LParen => {
depth += 1;
let kind = self.current().kind.clone();
self.advance();
tokens.push(MacroToken::Literal(kind));
}
TokenKind::RParen => {
depth -= 1;
if depth == 0 {
break;
}
let kind = self.current().kind.clone();
self.advance();
tokens.push(MacroToken::Literal(kind));
}
_ => {
tokens.push(self.parse_macro_token()?);
}
}
}
Ok(tokens)
}
fn parse_quoted_tokens(&mut self) -> Result<Vec<MacroToken>, ParseError> {
let mut tokens = Vec::new();
let mut depth = 1u32;
while !self.is_eof() {
if matches!(self.current().kind, TokenKind::LParen) {
depth += 1;
} else if matches!(self.current().kind, TokenKind::RParen) {
depth -= 1;
if depth == 0 {
break;
}
}
tokens.push(self.parse_macro_token()?);
}
Ok(tokens)
}
fn is_delimiter(&self) -> bool {
matches!(
self.current().kind,
TokenKind::Arrow | TokenKind::Semicolon | TokenKind::RParen | TokenKind::Bar
)
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub struct DepthLimitedExpander {
pub max_depth: usize,
pub current_depth: usize,
}
impl DepthLimitedExpander {
#[allow(dead_code)]
pub fn new(max_depth: usize) -> Self {
DepthLimitedExpander {
max_depth,
current_depth: 0,
}
}
#[allow(dead_code)]
pub fn try_expand(&mut self) -> bool {
if self.current_depth >= self.max_depth {
return false;
}
self.current_depth += 1;
true
}
#[allow(dead_code)]
pub fn exit(&mut self) {
if self.current_depth > 0 {
self.current_depth -= 1;
}
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct HygieneContext {
pub depth: usize,
pub tag: u64,
}
impl HygieneContext {
#[allow(dead_code)]
pub fn new(tag: u64) -> Self {
HygieneContext { depth: 0, tag }
}
#[allow(dead_code)]
pub fn nested(&self) -> Self {
HygieneContext {
depth: self.depth + 1,
tag: self.tag,
}
}
#[allow(dead_code)]
pub fn hygienic_name(&self, name: &str) -> String {
format!("{}__{}_{}", name, self.tag, self.depth)
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct MacroCallSiteExt {
pub macro_name: String,
pub args: Vec<String>,
pub offset: usize,
}
impl MacroCallSiteExt {
#[allow(dead_code)]
pub fn new(macro_name: &str, args: Vec<&str>, offset: usize) -> Self {
MacroCallSiteExt {
macro_name: macro_name.to_string(),
args: args.into_iter().map(|s| s.to_string()).collect(),
offset,
}
}
}
#[derive(Debug, Clone)]
pub struct MacroError {
pub kind: MacroErrorKind,
pub span: Option<Span>,
pub message: String,
}
impl MacroError {
pub fn new(kind: MacroErrorKind, message: String) -> Self {
Self {
kind,
span: None,
message,
}
}
pub fn with_span(mut self, span: Span) -> Self {
self.span = Some(span);
self
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub struct MacroEnvironmentExt {
pub macros: Vec<MacroDefinitionExt>,
}
impl MacroEnvironmentExt {
#[allow(dead_code)]
pub fn new() -> Self {
MacroEnvironmentExt { macros: Vec::new() }
}
#[allow(dead_code)]
pub fn define(&mut self, def: MacroDefinitionExt) {
self.macros.push(def);
}
#[allow(dead_code)]
pub fn find(&self, name: &str) -> Option<&MacroDefinitionExt> {
self.macros.iter().find(|m| m.name == name)
}
#[allow(dead_code)]
pub fn expand_call(&self, name: &str, args: &[&str]) -> Option<String> {
self.find(name).map(|m| m.expand(args))
}
#[allow(dead_code)]
pub fn len(&self) -> usize {
self.macros.len()
}
#[allow(dead_code)]
pub fn is_empty(&self) -> bool {
self.macros.is_empty()
}
}