diff --git a/book/src/list-units.md b/book/src/list-units.md index e3210c36..e0d81319 100644 --- a/book/src/list-units.md +++ b/book/src/list-units.md @@ -130,7 +130,7 @@ and — where sensible — units allow for [binary prefixes](https://en.wikipedi | `Money` | [Czech koruna](https://en.wikipedia.org/wiki/Czech_koruna) | `czech_koruna`, `czech_korunas`, `CZK`, `czk`, `Kč` | | `Money` | [Danish krone](https://en.wikipedia.org/wiki/Danish_krone) | `danish_krone`, `danish_kroner`, `DKK`, `dkk` | | `Money` | [US dollar](https://en.wikipedia.org/wiki/United_States_dollar) | `$`, `dollar`, `dollars`, `USD`, `usd` | -| `Money` | [Euro](https://en.wikipedia.org/wiki/Euro) | `EUR`, `euro`, `euros`, `€` | +| `Money` | [Euro](https://en.wikipedia.org/wiki/Euro) | `EUR`, `eur`, `euro`, `euros`, `€` | | `Money` | [Hong Kong dollar](https://en.wikipedia.org/wiki/Hong_Kong_dollar) | `HK$`, `hk$`, `HKD`, `hkd`, `hong_kong_dollar`, `hong_kong_dollars` | | `Money` | [Hungarian forint](https://en.wikipedia.org/wiki/Hungarian_forint) | `Ft`, `HUF`, `huf`, `hungarian_forint`, `hungarian_forints` | | `Money` | [Icelandic króna](https://en.wikipedia.org/wiki/Icelandic_króna) | `icelandic_krona`, `icelandic_kronur`, `icelandic_króna`, `icelandic_krónur`, `ISK`, `isk` | diff --git a/numbat/modules/units/currency.nbt b/numbat/modules/units/currency.nbt index acc9f347..88ae12e7 100644 --- a/numbat/modules/units/currency.nbt +++ b/numbat/modules/units/currency.nbt @@ -3,7 +3,7 @@ dimension Money @name("Euro") @url("https://en.wikipedia.org/wiki/Euro") -@aliases(euros, EUR, €: short) +@aliases(euros, EUR, eur, €: short) unit euro: Money # See currencies.nbt for non-Euro currencies diff --git a/numbat/src/ast.rs b/numbat/src/ast.rs index 8078c063..2741e392 100644 --- a/numbat/src/ast.rs +++ b/numbat/src/ast.rs @@ -56,47 +56,52 @@ impl PrettyPrint for BinaryOperator { } #[derive(Debug, Clone, PartialEq)] -pub enum StringPart { +pub enum StringPart<'a> { Fixed(String), Interpolation { span: Span, - expr: Box, + expr: Box>, format_specifiers: Option, }, } #[derive(Debug, Clone, PartialEq)] -pub enum Expression { +pub enum Expression<'a> { Scalar(Span, Number), - Identifier(Span, String), + Identifier(Span, &'a str), UnitIdentifier(Span, Prefix, String, String), TypedHole(Span), UnaryOperator { op: UnaryOperator, - expr: Box, + expr: Box>, span_op: Span, }, BinaryOperator { op: BinaryOperator, - lhs: Box, - rhs: Box, + lhs: Box>, + rhs: Box>, span_op: Option, // not available for implicit multiplication and unicode exponents }, - FunctionCall(Span, Span, Box, Vec), + FunctionCall(Span, Span, Box>, Vec>), Boolean(Span, bool), - String(Span, Vec), - Condition(Span, Box, Box, Box), + String(Span, Vec>), + Condition( + Span, + Box>, + Box>, + Box>, + ), InstantiateStruct { full_span: Span, ident_span: Span, - name: String, - fields: Vec<(Span, String, Expression)>, + name: &'a str, + fields: Vec<(Span, &'a str, Expression<'a>)>, }, - AccessField(Span, Span, Box, String), - List(Span, Vec), + AccessField(Span, Span, Box>, &'a str), + List(Span, Vec>), } -impl Expression { +impl Expression<'_> { pub fn full_span(&self) -> Span { match self { Expression::Scalar(span, _) => *span, @@ -217,9 +222,9 @@ macro_rules! struct_ { crate::ast::Expression::InstantiateStruct { full_span: Span::dummy(), ident_span: Span::dummy(), - name: stringify!($name).to_owned(), + name: stringify!($name), fields: vec![ - $((Span::dummy(), stringify!($field).to_owned(), $val)),* + $((Span::dummy(), stringify!($field), $val)),* ] } }}; @@ -394,48 +399,48 @@ pub enum TypeParameterBound { } #[derive(Debug, Clone, PartialEq)] -pub struct DefineVariable { +pub struct DefineVariable<'a> { pub identifier_span: Span, - pub identifier: String, - pub expr: Expression, + pub identifier: &'a str, + pub expr: Expression<'a>, pub type_annotation: Option, - pub decorators: Vec, + pub decorators: Vec>, } #[derive(Debug, Clone, PartialEq)] -pub enum Statement { - Expression(Expression), - DefineVariable(DefineVariable), +pub enum Statement<'a> { + Expression(Expression<'a>), + DefineVariable(DefineVariable<'a>), DefineFunction { function_name_span: Span, - function_name: String, - type_parameters: Vec<(Span, String, Option)>, + function_name: &'a str, + type_parameters: Vec<(Span, &'a str, Option)>, /// Parameters, optionally with type annotations. - parameters: Vec<(Span, String, Option)>, + parameters: Vec<(Span, &'a str, Option)>, /// Function body. If it is absent, the function is implemented via FFI - body: Option, + body: Option>, /// Local variables - local_variables: Vec, + local_variables: Vec>, /// Optional annotated return type return_type_annotation: Option, - decorators: Vec, + decorators: Vec>, }, - DefineDimension(Span, String, Vec), - DefineBaseUnit(Span, String, Option, Vec), + DefineDimension(Span, &'a str, Vec), + DefineBaseUnit(Span, &'a str, Option, Vec>), DefineDerivedUnit { identifier_span: Span, - identifier: String, - expr: Expression, + identifier: &'a str, + expr: Expression<'a>, type_annotation_span: Option, type_annotation: Option, - decorators: Vec, + decorators: Vec>, }, - ProcedureCall(Span, ProcedureKind, Vec), + ProcedureCall(Span, ProcedureKind, Vec>), ModuleImport(Span, ModulePath), DefineStruct { struct_name_span: Span, - struct_name: String, - fields: Vec<(Span, String, TypeAnnotation)>, + struct_name: &'a str, + fields: Vec<(Span, &'a str, TypeAnnotation)>, }, } @@ -491,7 +496,7 @@ impl ReplaceSpans for TypeExpression { } #[cfg(test)] -impl ReplaceSpans for StringPart { +impl ReplaceSpans for StringPart<'_> { fn replace_spans(&self) -> Self { match self { f @ StringPart::Fixed(_) => f.clone(), @@ -509,11 +514,11 @@ impl ReplaceSpans for StringPart { } #[cfg(test)] -impl ReplaceSpans for Expression { +impl ReplaceSpans for Expression<'_> { fn replace_spans(&self) -> Self { match self { Expression::Scalar(_, name) => Expression::Scalar(Span::dummy(), *name), - Expression::Identifier(_, name) => Expression::Identifier(Span::dummy(), name.clone()), + Expression::Identifier(_, name) => Expression::Identifier(Span::dummy(), name), Expression::UnitIdentifier(_, prefix, name, full_name) => { Expression::UnitIdentifier(Span::dummy(), *prefix, name.clone(), full_name.clone()) } @@ -557,17 +562,17 @@ impl ReplaceSpans for Expression { Expression::InstantiateStruct { name, fields, .. } => Expression::InstantiateStruct { full_span: Span::dummy(), ident_span: Span::dummy(), - name: name.clone(), + name, fields: fields .iter() - .map(|(_, n, v)| (Span::dummy(), n.clone(), v.replace_spans())) + .map(|(_, n, v)| (Span::dummy(), *n, v.replace_spans())) .collect(), }, Expression::AccessField(_, _, expr, attr) => Expression::AccessField( Span::dummy(), Span::dummy(), Box::new(expr.replace_spans()), - attr.clone(), + attr, ), Expression::List(_, elements) => Expression::List( Span::dummy(), @@ -579,11 +584,11 @@ impl ReplaceSpans for Expression { } #[cfg(test)] -impl ReplaceSpans for DefineVariable { +impl ReplaceSpans for DefineVariable<'_> { fn replace_spans(&self) -> Self { Self { identifier_span: Span::dummy(), - identifier: self.identifier.clone(), + identifier: self.identifier, expr: self.expr.replace_spans(), type_annotation: self.type_annotation.as_ref().map(|t| t.replace_spans()), decorators: self.decorators.clone(), @@ -592,7 +597,7 @@ impl ReplaceSpans for DefineVariable { } #[cfg(test)] -impl ReplaceSpans for Statement { +impl ReplaceSpans for Statement<'_> { fn replace_spans(&self) -> Self { match self { Statement::Expression(expr) => Statement::Expression(expr.replace_spans()), @@ -610,17 +615,17 @@ impl ReplaceSpans for Statement { decorators, } => Statement::DefineFunction { function_name_span: Span::dummy(), - function_name: function_name.clone(), + function_name, type_parameters: type_parameters .iter() - .map(|(_, name, bound)| (Span::dummy(), name.clone(), bound.clone())) + .map(|(_, name, bound)| (Span::dummy(), *name, bound.clone())) .collect(), parameters: parameters .iter() .map(|(_, name, type_)| { ( Span::dummy(), - name.clone(), + *name, type_.as_ref().map(|t| t.replace_spans()), ) }) @@ -635,12 +640,12 @@ impl ReplaceSpans for Statement { }, Statement::DefineDimension(_, name, dexprs) => Statement::DefineDimension( Span::dummy(), - name.clone(), + name, dexprs.iter().map(|t| t.replace_spans()).collect(), ), Statement::DefineBaseUnit(_, name, type_, decorators) => Statement::DefineBaseUnit( Span::dummy(), - name.clone(), + name, type_.as_ref().map(|t| t.replace_spans()), decorators.clone(), ), @@ -653,7 +658,7 @@ impl ReplaceSpans for Statement { decorators, } => Statement::DefineDerivedUnit { identifier_span: Span::dummy(), - identifier: identifier.clone(), + identifier, expr: expr.replace_spans(), type_annotation_span: type_annotation_span.map(|_| Span::dummy()), type_annotation: type_annotation.as_ref().map(|t| t.replace_spans()), @@ -673,12 +678,10 @@ impl ReplaceSpans for Statement { .. } => Statement::DefineStruct { struct_name_span: Span::dummy(), - struct_name: struct_name.clone(), + struct_name, fields: fields .iter() - .map(|(_span, name, type_)| { - (Span::dummy(), name.clone(), type_.replace_spans()) - }) + .map(|(_span, name, type_)| (Span::dummy(), *name, type_.replace_spans())) .collect(), }, } @@ -686,7 +689,7 @@ impl ReplaceSpans for Statement { } #[cfg(test)] -impl ReplaceSpans for Vec { +impl ReplaceSpans for Vec> { fn replace_spans(&self) -> Self { self.iter().map(|s| s.replace_spans()).collect() } diff --git a/numbat/src/bytecode_interpreter.rs b/numbat/src/bytecode_interpreter.rs index 26bf00a5..cc1dfd44 100644 --- a/numbat/src/bytecode_interpreter.rs +++ b/numbat/src/bytecode_interpreter.rs @@ -283,12 +283,11 @@ impl BytecodeInterpreter { // For variables, we ignore the prefix info and only use the names let aliases = crate::decorator::name_and_aliases(identifier, decorators) - .map(|(name, _)| name) - .cloned() + .map(|(name, _)| name.to_owned()) .collect::>(); let metadata = LocalMetadata { - name: crate::decorator::name(decorators), - url: crate::decorator::url(decorators), + name: crate::decorator::name(decorators).map(ToOwned::to_owned), + url: crate::decorator::url(decorators).map(ToOwned::to_owned), description: crate::decorator::description(decorators), aliases: aliases.clone(), }; @@ -380,7 +379,7 @@ impl BytecodeInterpreter { } Statement::DefineBaseUnit(unit_name, decorators, annotation, type_) => { let aliases = decorator::name_and_aliases(unit_name, decorators) - .map(|(name, ap)| (name.clone(), ap)) + .map(|(name, ap)| (name.to_owned(), ap)) .collect(); self.vm @@ -394,11 +393,11 @@ impl BytecodeInterpreter { .map(|a| a.pretty_print()) .unwrap_or(type_.to_readable_type(dimension_registry, false)), aliases, - name: decorator::name(decorators), + name: decorator::name(decorators).map(ToOwned::to_owned), canonical_name: decorator::get_canonical_unit_name( unit_name, decorators, ), - url: decorator::url(decorators), + url: decorator::url(decorators).map(ToOwned::to_owned), description: decorator::description(decorators), binary_prefixes: decorators.contains(&Decorator::BinaryPrefixes), metric_prefixes: decorators.contains(&Decorator::MetricPrefixes), @@ -424,7 +423,7 @@ impl BytecodeInterpreter { _readable_type, ) => { let aliases = decorator::name_and_aliases(unit_name, decorators) - .map(|(name, ap)| (name.clone(), ap)) + .map(|(name, ap)| (name.to_owned(), ap)) .collect(); let constant_idx = self.vm.add_constant(Constant::Unit(Unit::new_base( @@ -450,9 +449,9 @@ impl BytecodeInterpreter { .map(|a| a.pretty_print()) .unwrap_or(type_.to_readable_type(dimension_registry, false)), aliases, - name: decorator::name(decorators), + name: decorator::name(decorators).map(ToOwned::to_owned), canonical_name: decorator::get_canonical_unit_name(unit_name, decorators), - url: decorator::url(decorators), + url: decorator::url(decorators).map(ToOwned::to_owned), description: decorator::description(decorators), binary_prefixes: decorators.contains(&Decorator::BinaryPrefixes), metric_prefixes: decorators.contains(&Decorator::MetricPrefixes), diff --git a/numbat/src/decorator.rs b/numbat/src/decorator.rs index 25b89a3a..a4355bc1 100644 --- a/numbat/src/decorator.rs +++ b/numbat/src/decorator.rs @@ -1,10 +1,10 @@ use crate::{prefix_parser::AcceptsPrefix, span::Span, unit::CanonicalName}; #[derive(Debug, Clone, PartialEq, Eq)] -pub enum Decorator { +pub enum Decorator<'a> { MetricPrefixes, BinaryPrefixes, - Aliases(Vec<(String, Option, Span)>), + Aliases(Vec<(&'a str, Option, Span)>), Url(String), Name(String), Description(String), @@ -19,9 +19,9 @@ pub enum Decorator { /// decide whether to yield `(&'a String, AcceptsPrefix)` or a `(&'a String, /// AcceptsPrefix, Span)`. fn name_and_aliases_inner<'a, T: 'a>( - name: &'a String, + name: &'a str, decorators: &'a [Decorator], - f: impl 'a + Fn(&'a String, AcceptsPrefix, Option) -> T, + f: impl 'a + Fn(&'a str, AcceptsPrefix, Option) -> T, ) -> impl 'a + Iterator { // contains all the aliases of `name`, starting with `name` itself let mut aliases_vec = vec![f(name, AcceptsPrefix::only_long(), None)]; @@ -30,7 +30,7 @@ fn name_and_aliases_inner<'a, T: 'a>( if let Decorator::Aliases(aliases) = decorator { for (n, ap, span) in aliases { let ap = ap.unwrap_or(AcceptsPrefix::only_long()); - if n == name { + if *n == name { // use the AcceptsPrefix from the alias, but the span from `name` // itself; this way we always report a conflicting `name` first // before reporting any of its aliases. in effect we swallow aliases @@ -48,18 +48,18 @@ fn name_and_aliases_inner<'a, T: 'a>( /// Returns iterator of `(name_or_alias, accepts_prefix)` for the given name pub fn name_and_aliases<'a>( - name: &'a String, + name: &'a str, decorators: &'a [Decorator], -) -> impl 'a + Iterator { +) -> impl 'a + Iterator { name_and_aliases_inner(name, decorators, |n, accepts_prefix, _| (n, accepts_prefix)) } /// Returns iterator of `(name_or_alias, accepts_prefix, span)` for the given name pub fn name_and_aliases_spans<'a>( - name: &'a String, + name: &'a str, name_span: Span, decorators: &'a [Decorator], -) -> impl 'a + Iterator { +) -> impl 'a + Iterator { name_and_aliases_inner(name, decorators, move |n, accepts_prefix, span| { (n, accepts_prefix, span.unwrap_or(name_span)) }) @@ -84,19 +84,19 @@ pub fn get_canonical_unit_name(unit_name: &str, decorators: &[Decorator]) -> Can } } -pub fn name(decorators: &[Decorator]) -> Option { +pub fn name<'a>(decorators: &'a [Decorator<'a>]) -> Option<&'a str> { for decorator in decorators { if let Decorator::Name(name) = decorator { - return Some(name.clone()); + return Some(name); } } None } -pub fn url(decorators: &[Decorator]) -> Option { +pub fn url<'a>(decorators: &'a [Decorator<'a>]) -> Option<&'a str> { for decorator in decorators { if let Decorator::Url(url) = decorator { - return Some(url.clone()); + return Some(url); } } None diff --git a/numbat/src/dimension.rs b/numbat/src/dimension.rs index f8f70904..850169eb 100644 --- a/numbat/src/dimension.rs +++ b/numbat/src/dimension.rs @@ -24,7 +24,7 @@ impl DimensionRegistry { .any(|(_, n, _)| n == name) { Ok(BaseRepresentation::from_factor(BaseRepresentationFactor( - name.clone(), + name.to_string(), Exponent::from_integer(1), ))) } else { diff --git a/numbat/src/ffi/plot.rs b/numbat/src/ffi/plot.rs index e0e04f53..71ce5377 100644 --- a/numbat/src/ffi/plot.rs +++ b/numbat/src/ffi/plot.rs @@ -99,9 +99,9 @@ pub fn show(args: Args) -> Result { // Dynamic dispatch hack since we don't have bounded polymorphism. // And no real support for generics in the FFI. let Value::StructInstance(info, _) = args.front().unwrap() else { - return Err(RuntimeError::UserError(format!( - "Unsupported argument to 'show'.", - ))); + return Err(RuntimeError::UserError( + "Unsupported argument to 'show'.".into(), + )); }; let plot = if info.name == "LinePlot" { diff --git a/numbat/src/lib.rs b/numbat/src/lib.rs index e4dbc398..ec56a233 100644 --- a/numbat/src/lib.rs +++ b/numbat/src/lib.rs @@ -539,20 +539,20 @@ impl Context { &mut self.resolver } - pub fn interpret( + pub fn interpret<'a>( &mut self, - code: &str, + code: &'a str, code_source: CodeSource, - ) -> Result<(Vec, InterpreterResult)> { + ) -> Result<(Vec>, InterpreterResult)> { self.interpret_with_settings(&mut InterpreterSettings::default(), code, code_source) } - pub fn interpret_with_settings( + pub fn interpret_with_settings<'a>( &mut self, settings: &mut InterpreterSettings, - code: &str, + code: &'a str, code_source: CodeSource, - ) -> Result<(Vec, InterpreterResult)> { + ) -> Result<(Vec>, InterpreterResult)> { let statements = self .resolver .resolve(code, code_source.clone()) @@ -635,6 +635,7 @@ impl Context { "renminbi", "元", "EUR", + "eur", "euro", "euros", "€", diff --git a/numbat/src/parser.rs b/numbat/src/parser.rs index 6fa34e52..946ba9be 100644 --- a/numbat/src/parser.rs +++ b/numbat/src/parser.rs @@ -255,7 +255,7 @@ impl ParseError { } type Result = std::result::Result; -type ParseResult = Result, (Vec, Vec)>; +type ParseResult<'a> = Result>, (Vec>, Vec)>; static PROCEDURES: &[TokenKind] = &[ TokenKind::ProcedurePrint, @@ -264,12 +264,12 @@ static PROCEDURES: &[TokenKind] = &[ TokenKind::ProcedureType, ]; -struct Parser { +struct Parser<'a> { current: usize, - decorator_stack: Vec, + decorator_stack: Vec>, } -impl Parser { +impl<'a> Parser<'a> { pub(crate) fn new() -> Self { Parser { current: 0, @@ -277,7 +277,7 @@ impl Parser { } } - fn skip_empty_lines(&mut self, tokens: &[Token]) { + fn skip_empty_lines<'b>(&mut self, tokens: &'b [Token<'a>]) { while self.match_exact(tokens, TokenKind::Newline).is_some() {} } @@ -286,7 +286,7 @@ impl Parser { /// will try to recover from the error and parse as many statements as possible /// while stacking all the errors in a `Vec`. At the end, it returns the complete /// list of statements parsed + the list of errors accumulated. - fn parse(&mut self, tokens: &[Token]) -> ParseResult { + fn parse(&mut self, tokens: &[Token<'a>]) -> ParseResult<'a> { let mut statements = vec![]; let mut errors = vec![]; @@ -345,7 +345,7 @@ impl Parser { } } - fn accepts_prefix(&mut self, tokens: &[Token]) -> Result> { + fn accepts_prefix(&mut self, tokens: &[Token<'a>]) -> Result> { if self.match_exact(tokens, TokenKind::Colon).is_some() { if self.match_exact(tokens, TokenKind::Long).is_some() { Ok(Some(AcceptsPrefix::only_long())) @@ -368,15 +368,14 @@ impl Parser { fn list_of_aliases( &mut self, - tokens: &[Token], - ) -> Result, Span)>> { + tokens: &[Token<'a>], + ) -> Result, Span)>> { if self.match_exact(tokens, TokenKind::RightParen).is_some() { return Ok(vec![]); } let span = self.peek(tokens).span; - let mut identifiers: Vec<(String, Option, Span)> = - vec![(self.identifier(tokens)?, self.accepts_prefix(tokens)?, span)]; + let mut identifiers = vec![(self.identifier(tokens)?, self.accepts_prefix(tokens)?, span)]; while self.match_exact(tokens, TokenKind::Comma).is_some() { let span = self.peek(tokens).span; @@ -393,7 +392,7 @@ impl Parser { Ok(identifiers) } - fn statement(&mut self, tokens: &[Token]) -> Result { + fn statement(&mut self, tokens: &[Token<'a>]) -> Result> { if !(self.peek(tokens).kind == TokenKind::At || self.peek(tokens).kind == TokenKind::Unit || self.peek(tokens).kind == TokenKind::Let @@ -430,9 +429,9 @@ impl Parser { fn parse_variable( &mut self, - tokens: &[Token], + tokens: &[Token<'a>], flush_decorators: bool, - ) -> Result { + ) -> Result> { if let Some(identifier) = self.match_exact(tokens, TokenKind::Identifier) { let identifier_span = self.last(tokens).unwrap().span; @@ -464,7 +463,7 @@ impl Parser { Ok(DefineVariable { identifier_span, - identifier: identifier.lexeme.to_owned(), + identifier: identifier.lexeme, expr, type_annotation, decorators, @@ -478,7 +477,7 @@ impl Parser { } } - fn parse_function_declaration(&mut self, tokens: &[Token]) -> Result { + fn parse_function_declaration(&mut self, tokens: &[Token<'a>]) -> Result> { if let Some(fn_name) = self.match_exact(tokens, TokenKind::Identifier) { let function_name_span = self.last(tokens).unwrap().span; let mut type_parameters = vec![]; @@ -512,7 +511,7 @@ impl Parser { }; let span = self.last(tokens).unwrap().span; - type_parameters.push((span, type_parameter_name.lexeme.to_string(), bound)); + type_parameters.push((span, type_parameter_name.lexeme, bound)); if self.match_exact(tokens, TokenKind::Comma).is_none() && self.peek(tokens).kind != TokenKind::GreaterThan @@ -551,7 +550,7 @@ impl Parser { None }; - parameters.push((span, param_name.lexeme.to_string(), param_type_dexpr)); + parameters.push((span, param_name.lexeme, param_type_dexpr)); parameter_span = parameter_span.extend(&self.last(tokens).unwrap().span); @@ -637,7 +636,7 @@ impl Parser { Ok(Statement::DefineFunction { function_name_span, - function_name: fn_name.lexeme.to_owned(), + function_name: fn_name.lexeme, type_parameters, parameters, body, @@ -653,7 +652,7 @@ impl Parser { } } - fn parse_dimension_declaration(&mut self, tokens: &[Token]) -> Result { + fn parse_dimension_declaration(&mut self, tokens: &[Token<'a>]) -> Result> { if let Some(identifier) = self.match_exact(tokens, TokenKind::Identifier) { if identifier.lexeme.starts_with("__") { return Err(ParseError::new( @@ -673,13 +672,13 @@ impl Parser { Ok(Statement::DefineDimension( identifier.span, - identifier.lexeme.to_owned(), + identifier.lexeme, dexprs, )) } else { Ok(Statement::DefineDimension( identifier.span, - identifier.lexeme.to_owned(), + identifier.lexeme, vec![], )) } @@ -691,7 +690,7 @@ impl Parser { } } - fn parse_decorators(&mut self, tokens: &[Token]) -> Result { + fn parse_decorators(&mut self, tokens: &[Token<'a>]) -> Result> { if let Some(decorator) = self.match_exact(tokens, TokenKind::Identifier) { let decorator = match decorator.lexeme { "metric_prefixes" => Decorator::MetricPrefixes, @@ -759,7 +758,7 @@ impl Parser { } } - fn parse_unit_declaration(&mut self, tokens: &[Token]) -> Result { + fn parse_unit_declaration(&mut self, tokens: &[Token<'a>]) -> Result> { if let Some(identifier) = self.match_exact(tokens, TokenKind::Identifier) { let identifier_span = self.last(tokens).unwrap().span; let (type_annotation_span, dexpr) = @@ -770,7 +769,7 @@ impl Parser { (None, None) }; - let unit_name = identifier.lexeme.to_owned(); + let unit_name = identifier.lexeme; let mut decorators = vec![]; std::mem::swap(&mut decorators, &mut self.decorator_stack); @@ -814,7 +813,7 @@ impl Parser { } } - fn parse_use(&mut self, tokens: &[Token]) -> Result { + fn parse_use(&mut self, tokens: &[Token<'a>]) -> Result> { let mut span = self.peek(tokens).span; if let Some(identifier) = self.match_exact(tokens, TokenKind::Identifier) { @@ -841,7 +840,7 @@ impl Parser { } } - fn parse_struct(&mut self, tokens: &[Token]) -> Result { + fn parse_struct(&mut self, tokens: &[Token<'a>]) -> Result> { let name = self.identifier(tokens)?; let name_span = self.last(tokens).unwrap().span; @@ -890,7 +889,7 @@ impl Parser { }); } - fields.push((field_name.span, field_name.lexeme.to_owned(), attr_type)); + fields.push((field_name.span, field_name.lexeme, attr_type)); } Ok(Statement::DefineStruct { @@ -900,7 +899,7 @@ impl Parser { }) } - fn parse_procedure(&mut self, tokens: &[Token]) -> Result { + fn parse_procedure(&mut self, tokens: &[Token<'a>]) -> Result> { let span = self.last(tokens).unwrap().span; let procedure_kind = match self.last(tokens).unwrap().kind { TokenKind::ProcedurePrint => ProcedureKind::Print, @@ -930,11 +929,11 @@ impl Parser { /// - arg `next` specifiy the next parser to call between each symbols fn parse_binop( &mut self, - tokens: &[Token], + tokens: &[Token<'a>], op_symbol: &[TokenKind], op: impl Fn(TokenKind) -> BinaryOperator, - next_parser: impl Fn(&mut Self) -> Result, - ) -> Result { + next_parser: impl Fn(&mut Self) -> Result>, + ) -> Result> { let mut expr = next_parser(self)?; while let Some(matched) = self.match_any(tokens, op_symbol) { let span_op = Some(self.last(tokens).unwrap().span); @@ -950,13 +949,13 @@ impl Parser { Ok(expr) } - pub fn expression(&mut self, tokens: &[Token]) -> Result { + pub fn expression(&mut self, tokens: &[Token<'a>]) -> Result> { self.postfix_apply(tokens) } - fn identifier(&mut self, tokens: &[Token]) -> Result { + fn identifier(&mut self, tokens: &[Token<'a>]) -> Result<&'a str> { if let Some(identifier) = self.match_exact(tokens, TokenKind::Identifier) { - Ok(identifier.lexeme.to_owned()) + Ok(identifier.lexeme) } else { Err(ParseError::new( ParseErrorKind::ExpectedIdentifier, @@ -965,7 +964,7 @@ impl Parser { } } - pub fn postfix_apply(&mut self, tokens: &[Token]) -> Result { + pub fn postfix_apply(&mut self, tokens: &[Token<'a>]) -> Result> { let mut expr = self.condition(tokens)?; let mut full_span = expr.full_span(); while self.match_exact(tokens, TokenKind::PostfixApply).is_some() { @@ -998,7 +997,7 @@ impl Parser { Ok(expr) } - fn condition(&mut self, tokens: &[Token]) -> Result { + fn condition(&mut self, tokens: &[Token<'a>]) -> Result> { if self.match_exact(tokens, TokenKind::If).is_some() { let span_if = self.last(tokens).unwrap().span; let condition_expr = self.conversion(tokens)?; @@ -1040,7 +1039,7 @@ impl Parser { } } - fn conversion(&mut self, tokens: &[Token]) -> Result { + fn conversion(&mut self, tokens: &[Token<'a>]) -> Result> { self.parse_binop( tokens, &[TokenKind::Arrow, TokenKind::To], @@ -1049,7 +1048,7 @@ impl Parser { ) } - fn logical_or(&mut self, tokens: &[Token]) -> Result { + fn logical_or(&mut self, tokens: &[Token<'a>]) -> Result> { self.parse_binop( tokens, &[TokenKind::LogicalOr], @@ -1058,7 +1057,7 @@ impl Parser { ) } - fn logical_and(&mut self, tokens: &[Token]) -> Result { + fn logical_and(&mut self, tokens: &[Token<'a>]) -> Result> { self.parse_binop( tokens, &[TokenKind::LogicalAnd], @@ -1067,7 +1066,7 @@ impl Parser { ) } - fn logical_neg(&mut self, tokens: &[Token]) -> Result { + fn logical_neg(&mut self, tokens: &[Token<'a>]) -> Result> { if self .match_exact(tokens, TokenKind::ExclamationMark) .is_some() @@ -1085,7 +1084,7 @@ impl Parser { } } - fn comparison(&mut self, tokens: &[Token]) -> Result { + fn comparison(&mut self, tokens: &[Token<'a>]) -> Result> { self.parse_binop( tokens, &[ @@ -1109,7 +1108,7 @@ impl Parser { ) } - fn term(&mut self, tokens: &[Token]) -> Result { + fn term(&mut self, tokens: &[Token<'a>]) -> Result> { self.parse_binop( tokens, &[TokenKind::Plus, TokenKind::Minus], @@ -1122,7 +1121,7 @@ impl Parser { ) } - fn factor(&mut self, tokens: &[Token]) -> Result { + fn factor(&mut self, tokens: &[Token<'a>]) -> Result> { self.parse_binop( tokens, &[TokenKind::Multiply, TokenKind::Divide], @@ -1135,7 +1134,7 @@ impl Parser { ) } - fn per_factor(&mut self, tokens: &[Token]) -> Result { + fn per_factor(&mut self, tokens: &[Token<'a>]) -> Result> { self.parse_binop( tokens, &[TokenKind::Per], @@ -1144,7 +1143,7 @@ impl Parser { ) } - fn unary(&mut self, tokens: &[Token]) -> Result { + fn unary(&mut self, tokens: &[Token<'a>]) -> Result> { if self.match_exact(tokens, TokenKind::Minus).is_some() { let span = self.last(tokens).unwrap().span; let rhs = self.unary(tokens)?; @@ -1163,7 +1162,7 @@ impl Parser { } } - fn ifactor(&mut self, tokens: &[Token]) -> Result { + fn ifactor(&mut self, tokens: &[Token<'a>]) -> Result> { let mut expr = self.power(tokens)?; while self.next_token_could_start_power_expression(tokens) { @@ -1179,7 +1178,7 @@ impl Parser { Ok(expr) } - fn power(&mut self, tokens: &[Token]) -> Result { + fn power(&mut self, tokens: &[Token<'a>]) -> Result> { let mut expr = self.factorial(tokens)?; if self.match_exact(tokens, TokenKind::Power).is_some() { @@ -1214,7 +1213,7 @@ impl Parser { Ok(expr) } - fn factorial(&mut self, tokens: &[Token]) -> Result { + fn factorial(&mut self, tokens: &[Token<'a>]) -> Result> { let mut expr = self.unicode_power(tokens)?; while self @@ -1259,7 +1258,7 @@ impl Parser { } } - fn unicode_power(&mut self, tokens: &[Token]) -> Result { + fn unicode_power(&mut self, tokens: &[Token<'a>]) -> Result> { let mut expr = self.call(tokens)?; if let Some(exponent) = self.match_exact(tokens, TokenKind::UnicodeExponent) { @@ -1279,7 +1278,7 @@ impl Parser { Ok(expr) } - fn call(&mut self, tokens: &[Token]) -> Result { + fn call(&mut self, tokens: &[Token<'a>]) -> Result> { let mut expr = self.primary(tokens)?; loop { @@ -1303,13 +1302,13 @@ impl Parser { } } - fn arguments(&mut self, tokens: &[Token]) -> Result> { + fn arguments(&mut self, tokens: &[Token<'a>]) -> Result>> { self.skip_empty_lines(tokens); if self.match_exact(tokens, TokenKind::RightParen).is_some() { return Ok(vec![]); } - let mut args: Vec = vec![self.expression(tokens)?]; + let mut args = vec![self.expression(tokens)?]; loop { self.skip_empty_lines(tokens); @@ -1340,7 +1339,7 @@ impl Parser { Ok(args) } - fn primary(&mut self, tokens: &[Token]) -> Result { + fn primary(&mut self, tokens: &[Token<'a>]) -> Result> { // This function needs to be kept in sync with `next_token_could_start_power_expression` below. let overflow_error = |span| { @@ -1461,7 +1460,7 @@ impl Parser { }); } - fields.push((field_name.span, field_name.lexeme.to_owned(), expr)); + fields.push((field_name.span, field_name.lexeme, expr)); } let full_span = span.extend(&self.last(tokens).unwrap().span); @@ -1469,12 +1468,12 @@ impl Parser { return Ok(Expression::InstantiateStruct { full_span, ident_span: span, - name: identifier.lexeme.to_owned(), + name: identifier.lexeme, fields, }); } - Ok(Expression::Identifier(span, identifier.lexeme.to_owned())) + Ok(Expression::Identifier(span, identifier.lexeme)) } else if let Some(inner) = self.match_any(tokens, &[TokenKind::True, TokenKind::False]) { Ok(Expression::Boolean( inner.span, @@ -1572,9 +1571,9 @@ impl Parser { fn interpolation( &mut self, - tokens: &[Token], - parts: &mut Vec, - token: &Token, + tokens: &[Token<'a>], + parts: &mut Vec>, + token: &Token<'a>, ) -> Result<()> { parts.push(StringPart::Fixed(strip_and_escape(token.lexeme))); @@ -1607,7 +1606,7 @@ impl Parser { ) } - fn type_annotation(&mut self, tokens: &[Token]) -> Result { + fn type_annotation(&mut self, tokens: &[Token<'a>]) -> Result { if let Some(token) = self.match_exact(tokens, TokenKind::Bool) { Ok(TypeAnnotation::Bool(token.span)) } else if let Some(token) = self.match_exact(tokens, TokenKind::String) { @@ -1692,11 +1691,11 @@ impl Parser { } } - fn dimension_expression(&mut self, tokens: &[Token]) -> Result { + fn dimension_expression(&mut self, tokens: &[Token<'a>]) -> Result { self.dimension_factor(tokens) } - fn dimension_factor(&mut self, tokens: &[Token]) -> Result { + fn dimension_factor(&mut self, tokens: &[Token<'a>]) -> Result { let mut expr = self.dimension_power(tokens)?; while let Some(operator_token) = self.match_any(tokens, &[TokenKind::Multiply, TokenKind::Divide]) @@ -1713,7 +1712,7 @@ impl Parser { Ok(expr) } - fn dimension_power(&mut self, tokens: &[Token]) -> Result { + fn dimension_power(&mut self, tokens: &[Token<'a>]) -> Result { let expr = self.dimension_primary(tokens)?; if self.match_exact(tokens, TokenKind::Power).is_some() { @@ -1741,7 +1740,7 @@ impl Parser { } } - fn dimension_exponent(&mut self, tokens: &[Token]) -> Result<(Span, Exponent)> { + fn dimension_exponent(&mut self, tokens: &[Token<'a>]) -> Result<(Span, Exponent)> { if let Some(token) = self.match_exact(tokens, TokenKind::Number) { let span = self.last(tokens).unwrap().span; let num_str = token.lexeme.replace('_', ""); @@ -1803,7 +1802,7 @@ impl Parser { } } - fn dimension_primary(&mut self, tokens: &[Token]) -> Result { + fn dimension_primary(&mut self, tokens: &[Token<'a>]) -> Result { let e = Err(ParseError::new( ParseErrorKind::ExpectedDimensionPrimary, self.peek(tokens).span, @@ -1841,11 +1840,11 @@ impl Parser { } } - fn match_exact<'a>( + fn match_exact<'b>( &mut self, - tokens: &'a [Token<'a>], + tokens: &'b [Token<'a>], token_kind: TokenKind, - ) -> Option<&'a Token<'a>> { + ) -> Option<&'b Token<'a>> { let token = self.peek(tokens); if token.kind == token_kind { self.advance(tokens); @@ -1868,22 +1867,22 @@ impl Parser { /// Same as 'match_exact', but skips empty lines before matching. Note that this /// does *not* skip empty lines in case there is no match. - fn match_exact_beyond_linebreaks<'a>( + fn match_exact_beyond_linebreaks<'b>( &mut self, - tokens: &'a [Token<'a>], + tokens: &'b [Token<'a>], token_kind: TokenKind, - ) -> Option<&'a Token<'a>> { + ) -> Option<&'b Token<'a>> { if self.look_ahead_beyond_linebreak(tokens, token_kind) { self.skip_empty_lines(tokens); } self.match_exact(tokens, token_kind) } - fn match_any<'a>( + fn match_any<'b>( &mut self, - tokens: &'a [Token<'a>], + tokens: &'b [Token<'a>], kinds: &[TokenKind], - ) -> Option<&'a Token<'a>> { + ) -> Option<&'b Token<'a>> { for kind in kinds { if let result @ Some(..) = self.match_exact(tokens, *kind) { return result; @@ -1898,11 +1897,11 @@ impl Parser { } } - fn peek<'a>(&self, tokens: &'a [Token<'a>]) -> &'a Token<'a> { + fn peek<'b>(&self, tokens: &'b [Token<'a>]) -> &'b Token<'a> { &tokens[self.current] } - fn last<'a>(&self, tokens: &'a [Token<'a>]) -> Option<&'a Token<'a>> { + fn last<'b>(&self, tokens: &'b [Token<'a>]) -> Option<&'b Token<'a>> { if self.current == 0 { None } else { @@ -1960,7 +1959,7 @@ fn strip_and_escape(s: &str) -> String { /// will try to recover from the error and parse as many statements as possible /// while stacking all the errors in a `Vec`. At the end, it returns the complete /// list of statements parsed + the list of errors accumulated. -pub fn parse(input: &str, code_source_id: usize) -> ParseResult { +pub fn parse(input: &str, code_source_id: usize) -> ParseResult<'_> { use crate::tokenizer::tokenize; let tokens = tokenize(input, code_source_id) @@ -1968,8 +1967,10 @@ pub fn parse(input: &str, code_source_id: usize) -> ParseResult { ParseError::new(ParseErrorKind::TokenizerError(kind), span) }) .map_err(|e| (Vec::new(), vec![e]))?; + let tokens = &tokens; + let mut parser = Parser::new(); - parser.parse(&tokens) + parser.parse(tokens) } #[cfg(test)] @@ -2411,7 +2412,7 @@ mod tests { &["let foo = 1", "let foo=1"], Statement::DefineVariable(DefineVariable { identifier_span: Span::dummy(), - identifier: "foo".into(), + identifier: "foo", expr: scalar!(1.0), type_annotation: None, decorators: Vec::new(), @@ -2422,7 +2423,7 @@ mod tests { &["let x: Length = 1 * meter"], Statement::DefineVariable(DefineVariable { identifier_span: Span::dummy(), - identifier: "x".into(), + identifier: "x", expr: binop!(scalar!(1.0), Mul, identifier!("meter")), type_annotation: Some(TypeAnnotation::TypeExpression( TypeExpression::TypeIdentifier(Span::dummy(), "Length".into()), @@ -2436,7 +2437,7 @@ mod tests { &["@name(\"myvar\") @aliases(foo, bar) let x: Length = 1 * meter"], Statement::DefineVariable(DefineVariable { identifier_span: Span::dummy(), - identifier: "x".into(), + identifier: "x", expr: binop!(scalar!(1.0), Mul, identifier!("meter")), type_annotation: Some(TypeAnnotation::TypeExpression( TypeExpression::TypeIdentifier(Span::dummy(), "Length".into()), @@ -2445,7 +2446,7 @@ mod tests { decorator::Decorator::Name("myvar".into()), decorator::Decorator::Aliases(vec![ ( - "foo".into(), + "foo", None, Span { start: ByteIndex(24), @@ -2454,7 +2455,7 @@ mod tests { }, ), ( - "bar".into(), + "bar", None, Span { start: ByteIndex(29), @@ -2494,7 +2495,7 @@ mod tests { fn dimension_definition() { parse_as( &["dimension px"], - Statement::DefineDimension(Span::dummy(), "px".into(), vec![]), + Statement::DefineDimension(Span::dummy(), "px", vec![]), ); parse_as( @@ -2505,7 +2506,7 @@ mod tests { ], Statement::DefineDimension( Span::dummy(), - "Area".into(), + "Area", vec![TypeExpression::Multiply( Span::dummy(), Box::new(TypeExpression::TypeIdentifier( @@ -2524,7 +2525,7 @@ mod tests { &["dimension Velocity = Length / Time"], Statement::DefineDimension( Span::dummy(), - "Velocity".into(), + "Velocity", vec![TypeExpression::Divide( Span::dummy(), Box::new(TypeExpression::TypeIdentifier( @@ -2540,7 +2541,7 @@ mod tests { &["dimension Area = Length^2"], Statement::DefineDimension( Span::dummy(), - "Area".into(), + "Area", vec![TypeExpression::Power( Some(Span::dummy()), Box::new(TypeExpression::TypeIdentifier( @@ -2557,7 +2558,7 @@ mod tests { &["dimension Energy = Mass * Length^2 / Time^2"], Statement::DefineDimension( Span::dummy(), - "Energy".into(), + "Energy", vec![TypeExpression::Divide( Span::dummy(), Box::new(TypeExpression::Multiply( @@ -2587,7 +2588,7 @@ mod tests { &["dimension X = Length^(12345/67890)"], Statement::DefineDimension( Span::dummy(), - "X".into(), + "X", vec![TypeExpression::Power( Some(Span::dummy()), Box::new(TypeExpression::TypeIdentifier( @@ -2613,7 +2614,7 @@ mod tests { &["fn foo() = 1", "fn foo() =\n 1"], Statement::DefineFunction { function_name_span: Span::dummy(), - function_name: "foo".into(), + function_name: "foo", type_parameters: vec![], parameters: vec![], body: Some(scalar!(1.0)), @@ -2627,7 +2628,7 @@ mod tests { &["fn foo() -> Scalar = 1"], Statement::DefineFunction { function_name_span: Span::dummy(), - function_name: "foo".into(), + function_name: "foo", type_parameters: vec![], parameters: vec![], body: Some(scalar!(1.0)), @@ -2643,9 +2644,9 @@ mod tests { &["fn foo(x) = 1"], Statement::DefineFunction { function_name_span: Span::dummy(), - function_name: "foo".into(), + function_name: "foo", type_parameters: vec![], - parameters: vec![(Span::dummy(), "x".into(), None)], + parameters: vec![(Span::dummy(), "x", None)], body: Some(scalar!(1.0)), local_variables: vec![], return_type_annotation: None, @@ -2657,9 +2658,9 @@ mod tests { &["fn foo(x,) = 1"], Statement::DefineFunction { function_name_span: Span::dummy(), - function_name: "foo".into(), + function_name: "foo", type_parameters: vec![], - parameters: vec![(Span::dummy(), "x".into(), None)], + parameters: vec![(Span::dummy(), "x", None)], body: Some(scalar!(1.0)), local_variables: vec![], return_type_annotation: None, @@ -2674,12 +2675,9 @@ mod tests { ) = 1"], Statement::DefineFunction { function_name_span: Span::dummy(), - function_name: "foo".into(), + function_name: "foo", type_parameters: vec![], - parameters: vec![ - (Span::dummy(), "x".into(), None), - (Span::dummy(), "y".into(), None), - ], + parameters: vec![(Span::dummy(), "x", None), (Span::dummy(), "y", None)], body: Some(scalar!(1.0)), local_variables: vec![], return_type_annotation: None, @@ -2691,12 +2689,12 @@ mod tests { &["fn foo(x, y, z) = 1"], Statement::DefineFunction { function_name_span: Span::dummy(), - function_name: "foo".into(), + function_name: "foo", type_parameters: vec![], parameters: vec![ - (Span::dummy(), "x".into(), None), - (Span::dummy(), "y".into(), None), - (Span::dummy(), "z".into(), None), + (Span::dummy(), "x", None), + (Span::dummy(), "y", None), + (Span::dummy(), "z", None), ], body: Some(scalar!(1.0)), local_variables: vec![], @@ -2709,26 +2707,26 @@ mod tests { &["fn foo(x: Length, y: Time, z: Length^3 · Time^2) -> Scalar = 1"], Statement::DefineFunction { function_name_span: Span::dummy(), - function_name: "foo".into(), + function_name: "foo", type_parameters: vec![], parameters: vec![ ( Span::dummy(), - "x".into(), + "x", Some(TypeAnnotation::TypeExpression( TypeExpression::TypeIdentifier(Span::dummy(), "Length".into()), )), ), ( Span::dummy(), - "y".into(), + "y", Some(TypeAnnotation::TypeExpression( TypeExpression::TypeIdentifier(Span::dummy(), "Time".into()), )), ), ( Span::dummy(), - "z".into(), + "z", Some(TypeAnnotation::TypeExpression(TypeExpression::Multiply( Span::dummy(), Box::new(TypeExpression::Power( @@ -2765,11 +2763,11 @@ mod tests { &["fn foo(x: X) = 1"], Statement::DefineFunction { function_name_span: Span::dummy(), - function_name: "foo".into(), - type_parameters: vec![(Span::dummy(), "X".into(), None)], + function_name: "foo", + type_parameters: vec![(Span::dummy(), "X", None)], parameters: vec![( Span::dummy(), - "x".into(), + "x", Some(TypeAnnotation::TypeExpression( TypeExpression::TypeIdentifier(Span::dummy(), "X".into()), )), @@ -2785,11 +2783,11 @@ mod tests { &["fn foo(x: X) = 1"], Statement::DefineFunction { function_name_span: Span::dummy(), - function_name: "foo".into(), - type_parameters: vec![(Span::dummy(), "X".into(), Some(TypeParameterBound::Dim))], + function_name: "foo", + type_parameters: vec![(Span::dummy(), "X", Some(TypeParameterBound::Dim))], parameters: vec![( Span::dummy(), - "x".into(), + "x", Some(TypeAnnotation::TypeExpression( TypeExpression::TypeIdentifier(Span::dummy(), "X".into()), )), @@ -2805,9 +2803,9 @@ mod tests { &["@name(\"Some function\") @description(\"This is a description of some_function.\") fn some_function(x) = 1"], Statement::DefineFunction { function_name_span: Span::dummy(), - function_name: "some_function".into(), + function_name: "some_function", type_parameters: vec![], - parameters: vec![(Span::dummy(), "x".into(), None)], + parameters: vec![(Span::dummy(), "x", None)], body: Some(scalar!(1.0)), local_variables: vec![], return_type_annotation: None, @@ -2824,13 +2822,13 @@ mod tests { &["fn double_kef(x) = y where y = x * 2"], Statement::DefineFunction { function_name_span: Span::dummy(), - function_name: "double_kef".into(), + function_name: "double_kef", type_parameters: vec![], - parameters: vec![(Span::dummy(), "x".into(), None)], + parameters: vec![(Span::dummy(), "x", None)], body: Some(identifier!("y")), local_variables: vec![DefineVariable { identifier_span: Span::dummy(), - identifier: String::from("y"), + identifier: "y", expr: binop!(identifier!("x"), Mul, scalar!(2.0)), type_annotation: None, decorators: vec![], @@ -2846,21 +2844,21 @@ mod tests { and z = y + x"], Statement::DefineFunction { function_name_span: Span::dummy(), - function_name: "kefirausaure".into(), + function_name: "kefirausaure", type_parameters: vec![], - parameters: vec![(Span::dummy(), "x".into(), None)], + parameters: vec![(Span::dummy(), "x", None)], body: Some(binop!(identifier!("z"), Add, identifier!("y"))), local_variables: vec![ DefineVariable { identifier_span: Span::dummy(), - identifier: String::from("y"), + identifier: "y", expr: binop!(identifier!("x"), Add, identifier!("x")), type_annotation: None, decorators: vec![], }, DefineVariable { identifier_span: Span::dummy(), - identifier: String::from("z"), + identifier: "z", expr: binop!(identifier!("y"), Add, identifier!("x")), type_annotation: None, decorators: vec![], @@ -3329,11 +3327,11 @@ mod tests { &["struct Foo { foo: Scalar, bar: Scalar }"], Statement::DefineStruct { struct_name_span: Span::dummy(), - struct_name: "Foo".to_owned(), + struct_name: "Foo", fields: vec![ ( Span::dummy(), - "foo".to_owned(), + "foo", TypeAnnotation::TypeExpression(TypeExpression::TypeIdentifier( Span::dummy(), "Scalar".to_owned(), @@ -3341,7 +3339,7 @@ mod tests { ), ( Span::dummy(), - "bar".to_owned(), + "bar", TypeAnnotation::TypeExpression(TypeExpression::TypeIdentifier( Span::dummy(), "Scalar".to_owned(), @@ -3370,7 +3368,7 @@ mod tests { foo: scalar!(1.0), bar: scalar!(2.0) }), - "foo".to_owned(), + "foo", ), ); } diff --git a/numbat/src/prefix_parser.rs b/numbat/src/prefix_parser.rs index 13596712..2a21e555 100644 --- a/numbat/src/prefix_parser.rs +++ b/numbat/src/prefix_parser.rs @@ -8,8 +8,8 @@ use crate::{name_resolution::NameResolutionError, prefix::Prefix}; static PREFIXES: OnceLock> = OnceLock::new(); #[derive(Debug, Clone, PartialEq)] -pub enum PrefixParserResult { - Identifier(String), +pub enum PrefixParserResult<'a> { + Identifier(&'a str), /// Span, prefix, unit name in source (e.g. 'm'), full unit name (e.g. 'meter') UnitIdentifier(Span, Prefix, String, String), } @@ -250,7 +250,7 @@ impl PrefixParser { Ok(()) } - pub fn parse(&self, input: &str) -> PrefixParserResult { + pub fn parse<'a>(&self, input: &'a str) -> PrefixParserResult<'a> { if let Some(info) = self.units.get(input) { return PrefixParserResult::UnitIdentifier( info.definition_span, @@ -277,7 +277,7 @@ impl PrefixParser { return PrefixParserResult::UnitIdentifier( info.definition_span, *prefix, - unit_name.to_string(), + unit_name.clone(), info.full_name.clone(), ); } @@ -291,14 +291,14 @@ impl PrefixParser { return PrefixParserResult::UnitIdentifier( info.definition_span, *prefix, - unit_name.to_string(), + unit_name.clone(), info.full_name.clone(), ); } } } - PrefixParserResult::Identifier(input.into()) + PrefixParserResult::Identifier(input) } } @@ -538,38 +538,38 @@ mod tests { assert_eq!( prefix_parser.parse("kilom"), - PrefixParserResult::Identifier("kilom".into()) + PrefixParserResult::Identifier("kilom") ); assert_eq!( prefix_parser.parse("kilome"), - PrefixParserResult::Identifier("kilome".into()) + PrefixParserResult::Identifier("kilome") ); assert_eq!( prefix_parser.parse("kme"), - PrefixParserResult::Identifier("kme".into()) + PrefixParserResult::Identifier("kme") ); assert_eq!( prefix_parser.parse("kilomete"), - PrefixParserResult::Identifier("kilomete".into()) + PrefixParserResult::Identifier("kilomete") ); assert_eq!( prefix_parser.parse("kilometerr"), - PrefixParserResult::Identifier("kilometerr".into()) + PrefixParserResult::Identifier("kilometerr") ); assert_eq!( prefix_parser.parse("foometer"), - PrefixParserResult::Identifier("foometer".into()) + PrefixParserResult::Identifier("foometer") ); assert_eq!( prefix_parser.parse("kibimeter"), - PrefixParserResult::Identifier("kibimeter".into()) + PrefixParserResult::Identifier("kibimeter") ); assert_eq!( prefix_parser.parse("Kim"), - PrefixParserResult::Identifier("Kim".into()) + PrefixParserResult::Identifier("Kim") ); } } diff --git a/numbat/src/prefix_transformer.rs b/numbat/src/prefix_transformer.rs index 9c08a6e2..5db124c6 100644 --- a/numbat/src/prefix_transformer.rs +++ b/numbat/src/prefix_transformer.rs @@ -29,7 +29,7 @@ impl Transformer { } } - fn transform_expression(&self, expression: Expression) -> Expression { + fn transform_expression<'a>(&self, expression: Expression<'a>) -> Expression<'a> { match expression { expr @ Expression::Scalar(..) => expr, Expression::Identifier(span, identifier) => { @@ -38,7 +38,7 @@ impl Transformer { prefix, unit_name, full_name, - ) = self.prefix_parser.parse(&identifier) + ) = self.prefix_parser.parse(identifier) { Expression::UnitIdentifier(span, prefix, unit_name, full_name) } else { @@ -134,7 +134,7 @@ impl Transformer { pub(crate) fn register_name_and_aliases( &mut self, - name: &String, + name: &str, name_span: Span, decorators: &[Decorator], ) -> Result<()> { @@ -165,10 +165,10 @@ impl Transformer { Ok(()) } - fn transform_define_variable( + fn transform_define_variable<'a>( &mut self, - define_variable: DefineVariable, - ) -> Result { + define_variable: DefineVariable<'a>, + ) -> Result> { let DefineVariable { identifier_span, identifier, @@ -177,11 +177,11 @@ impl Transformer { decorators, } = define_variable; - for (name, _) in decorator::name_and_aliases(&identifier, &decorators) { - self.variable_names.push(name.clone()); + for (name, _) in decorator::name_and_aliases(identifier, &decorators) { + self.variable_names.push(name.to_owned()); } self.prefix_parser - .add_other_identifier(&identifier, identifier_span)?; + .add_other_identifier(identifier, identifier_span)?; Ok(DefineVariable { identifier_span, identifier, @@ -191,11 +191,11 @@ impl Transformer { }) } - fn transform_statement(&mut self, statement: Statement) -> Result { + fn transform_statement<'a>(&mut self, statement: Statement<'a>) -> Result> { Ok(match statement { Statement::Expression(expr) => Statement::Expression(self.transform_expression(expr)), Statement::DefineBaseUnit(span, name, dexpr, decorators) => { - self.register_name_and_aliases(&name, span, &decorators)?; + self.register_name_and_aliases(name, span, &decorators)?; Statement::DefineBaseUnit(span, name, dexpr, decorators) } Statement::DefineDerivedUnit { @@ -206,7 +206,7 @@ impl Transformer { type_annotation, decorators, } => { - self.register_name_and_aliases(&identifier, identifier_span, &decorators)?; + self.register_name_and_aliases(identifier, identifier_span, &decorators)?; Statement::DefineDerivedUnit { identifier_span, identifier, @@ -229,9 +229,9 @@ impl Transformer { return_type_annotation, decorators, } => { - self.function_names.push(function_name.clone()); + self.function_names.push(function_name.to_owned()); self.prefix_parser - .add_other_identifier(&function_name, function_name_span)?; + .add_other_identifier(function_name, function_name_span)?; // We create a clone of the full transformer for the purpose // of checking/transforming the function body. The reason for this @@ -272,7 +272,7 @@ impl Transformer { fields, }, Statement::DefineDimension(name_span, name, dexprs) => { - self.dimension_names.push(name.clone()); + self.dimension_names.push(name.to_owned()); Statement::DefineDimension(name_span, name, dexprs) } Statement::ProcedureCall(span, procedure, args) => Statement::ProcedureCall( @@ -286,10 +286,10 @@ impl Transformer { }) } - pub fn transform( + pub fn transform<'a>( &mut self, - statements: impl IntoIterator, - ) -> Result> { + statements: impl IntoIterator>, + ) -> Result>> { statements .into_iter() .map(|statement| self.transform_statement(statement)) diff --git a/numbat/src/resolver.rs b/numbat/src/resolver.rs index 5f653fd6..e581ce11 100644 --- a/numbat/src/resolver.rs +++ b/numbat/src/resolver.rs @@ -96,11 +96,11 @@ impl Resolver { self.codesources.get(&id).cloned().unwrap() } - fn parse(&self, code: &str, code_source_id: usize) -> Result> { + fn parse<'a>(&self, code: &'a str, code_source_id: usize) -> Result>> { parse(code, code_source_id).map_err(|e| ResolverError::ParseErrors(e.1)) } - fn inlining_pass(&mut self, program: &[Statement]) -> Result> { + fn inlining_pass<'a>(&mut self, program: &[Statement<'a>]) -> Result>> { let mut new_program = vec![]; for statement in program { @@ -108,13 +108,14 @@ impl Resolver { Statement::ModuleImport(span, module_path) => { if !self.imported_modules.contains(module_path) { if let Some((code, filesystem_path)) = self.importer.import(module_path) { + let code: &'static str = Box::leak(code.into_boxed_str()); self.imported_modules.push(module_path.clone()); let code_source_id = self.add_code_source( CodeSource::Module(module_path.clone(), filesystem_path), - &code, + code, ); - let imported_program = self.parse(&code, code_source_id)?; + let imported_program = self.parse(code, code_source_id)?; let inlined_program = self.inlining_pass(&imported_program)?; for statement in inlined_program { new_program.push(statement); @@ -131,7 +132,11 @@ impl Resolver { Ok(new_program) } - pub fn resolve(&mut self, code: &str, code_source: CodeSource) -> Result> { + pub fn resolve<'a>( + &mut self, + code: &'a str, + code_source: CodeSource, + ) -> Result>> { let code_source_id = self.add_code_source(code_source, code); let statements = self.parse(code, code_source_id)?; @@ -194,12 +199,12 @@ mod tests { &[ Statement::DefineVariable(DefineVariable { identifier_span: Span::dummy(), - identifier: "a".into(), + identifier: "a", expr: Expression::Scalar(Span::dummy(), Number::from_f64(1.0)), type_annotation: None, decorators: Vec::new(), }), - Statement::Expression(Expression::Identifier(Span::dummy(), "a".into())) + Statement::Expression(Expression::Identifier(Span::dummy(), "a")) ] ); } @@ -224,12 +229,12 @@ mod tests { &[ Statement::DefineVariable(DefineVariable { identifier_span: Span::dummy(), - identifier: "a".into(), + identifier: "a", expr: Expression::Scalar(Span::dummy(), Number::from_f64(1.0)), type_annotation: None, decorators: Vec::new(), }), - Statement::Expression(Expression::Identifier(Span::dummy(), "a".into())) + Statement::Expression(Expression::Identifier(Span::dummy(), "a")) ] ); } @@ -253,15 +258,15 @@ mod tests { &[ Statement::DefineVariable(DefineVariable { identifier_span: Span::dummy(), - identifier: "y".into(), + identifier: "y", expr: Expression::Scalar(Span::dummy(), Number::from_f64(1.0)), type_annotation: None, decorators: Vec::new(), }), Statement::DefineVariable(DefineVariable { identifier_span: Span::dummy(), - identifier: "x".into(), - expr: Expression::Identifier(Span::dummy(), "y".into()), + identifier: "x", + expr: Expression::Identifier(Span::dummy(), "y"), type_annotation: None, decorators: Vec::new(), }), diff --git a/numbat/src/traversal.rs b/numbat/src/traversal.rs index d3c679ac..c648ba32 100644 --- a/numbat/src/traversal.rs +++ b/numbat/src/traversal.rs @@ -75,7 +75,7 @@ impl ForAllTypeSchemes for Expression { } } -impl ForAllTypeSchemes for Statement { +impl ForAllTypeSchemes for Statement<'_> { fn for_all_type_schemes(&mut self, f: &mut dyn FnMut(&mut TypeScheme)) { match self { Statement::Expression(expr) => expr.for_all_type_schemes(f), @@ -115,7 +115,7 @@ pub trait ForAllExpressions { fn for_all_expressions(&self, f: &mut dyn FnMut(&Expression)); } -impl ForAllExpressions for Statement { +impl ForAllExpressions for Statement<'_> { fn for_all_expressions(&self, f: &mut dyn FnMut(&Expression)) { match self { Statement::Expression(expr) => expr.for_all_expressions(f), diff --git a/numbat/src/typechecker/environment.rs b/numbat/src/typechecker/environment.rs index d161dd0c..f37c2c45 100644 --- a/numbat/src/typechecker/environment.rs +++ b/numbat/src/typechecker/environment.rs @@ -28,8 +28,7 @@ impl FunctionSignature { let (fn_type, type_parameters) = self.fn_type.instantiate_for_printing(Some( self.type_parameters .iter() - .map(|(_, name, _)| name.clone()) - .collect(), + .map(|(_, name, _)| name.as_str()), )); let Type::Fn(ref parameter_types, ref return_type) = fn_type.inner else { @@ -45,7 +44,7 @@ impl FunctionSignature { Some(annotation) => annotation.pretty_print(), None => type_.to_readable_type(registry), }; - (name.clone(), readable_type) + (name.as_str(), readable_type) }); let readable_return_type = match &self.return_type_annotation { diff --git a/numbat/src/typechecker/mod.rs b/numbat/src/typechecker/mod.rs index cfd0917f..052cc240 100644 --- a/numbat/src/typechecker/mod.rs +++ b/numbat/src/typechecker/mod.rs @@ -67,7 +67,7 @@ pub struct TypeChecker { struct ElaborationDefinitionArgs<'a> { identifier_span: Span, - expr: &'a ast::Expression, + expr: &'a ast::Expression<'a>, type_annotation_span: Option, type_annotation: Option<&'a TypeAnnotation>, operation: &'a str, @@ -180,7 +180,7 @@ impl TypeChecker { ast::Expression::Identifier(_, name) => self .env .get_function_info(name) - .map(|(signature, _)| (name.clone(), signature)), + .map(|(signature, _)| (name.to_string(), signature)), _ => None, } } @@ -325,7 +325,7 @@ impl TypeChecker { } }; - typed_ast::Expression::Identifier(*span, name.clone(), TypeScheme::concrete(ty)) + typed_ast::Expression::Identifier(*span, name.to_string(), TypeScheme::concrete(ty)) } ast::Expression::UnitIdentifier(span, prefix, name, full_name) => { let type_scheme = self.identifier_type(*span, name)?.clone(); @@ -930,6 +930,7 @@ impl TypeChecker { name, fields, } => { + let name = *name; let fields_checked = fields .iter() .map(|(_, n, v)| Ok((n.to_string(), self.elaborate_expression(v)?))) @@ -938,7 +939,7 @@ impl TypeChecker { let Some(struct_info) = self.structs.get(name).cloned() else { return Err(Box::new(TypeCheckError::UnknownStruct( *ident_span, - name.clone(), + name.to_owned(), ))); }; @@ -1006,6 +1007,7 @@ impl TypeChecker { ) } ast::Expression::AccessField(full_span, ident_span, expr, field_name) => { + let field_name = *field_name; let expr_checked = self.elaborate_expression(expr)?; let type_ = expr_checked.get_type(); @@ -1036,7 +1038,7 @@ impl TypeChecker { self.constraints .add(Constraint::HasField( type_.clone(), - field_name.clone(), + field_name.to_owned(), field_type.clone(), )) .ok(); @@ -1175,10 +1177,10 @@ impl TypeChecker { Ok((expr_checked, type_deduced)) } - fn elaborate_define_variable( + fn elaborate_define_variable<'a>( &mut self, - define_variable: &ast::DefineVariable, - ) -> Result { + define_variable: &ast::DefineVariable<'a>, + ) -> Result> { let DefineVariable { identifier_span, identifier, @@ -1200,12 +1202,16 @@ impl TypeChecker { })?; for (name, _) in decorator::name_and_aliases(identifier, decorators) { - self.env - .add(name.clone(), type_deduced.clone(), *identifier_span, false); + self.env.add( + name.to_owned(), + type_deduced.clone(), + *identifier_span, + false, + ); self.value_namespace .add_identifier_allow_override( - name.clone(), + name.to_owned(), *identifier_span, "constant".to_owned(), ) @@ -1213,8 +1219,8 @@ impl TypeChecker { } Ok(typed_ast::DefineVariable( - identifier.clone(), - decorators.clone(), + identifier.to_string(), + decorators.to_owned(), expr_checked, type_annotation.clone(), TypeScheme::concrete(type_deduced), @@ -1222,7 +1228,10 @@ impl TypeChecker { )) } - fn elaborate_statement(&mut self, ast: &ast::Statement) -> Result { + fn elaborate_statement<'a>( + &mut self, + ast: &ast::Statement<'a>, + ) -> Result> { Ok(match ast { ast::Statement::Expression(expr) => { let checked_expr = self.elaborate_expression(expr)?; @@ -1250,7 +1259,7 @@ impl TypeChecker { if dtype.is_scalar() { return Err(Box::new(TypeCheckError::NoDimensionlessBaseUnit( *span, - unit_name.into(), + unit_name.to_string(), ))); } @@ -1267,7 +1276,7 @@ impl TypeChecker { }; for (name, _) in decorator::name_and_aliases(unit_name, decorators) { self.env.add( - name.clone(), + name.to_string(), Type::Dimension(type_specified.clone()), *span, true, @@ -1275,7 +1284,7 @@ impl TypeChecker { } typed_ast::Statement::DefineBaseUnit( - unit_name.clone(), + unit_name.to_string(), decorators.clone(), type_annotation.clone().map(TypeAnnotation::TypeExpression), TypeScheme::concrete(Type::Dimension(type_specified)), @@ -1303,11 +1312,15 @@ impl TypeChecker { })?; for (name, _) in decorator::name_and_aliases(identifier, decorators) { - self.env - .add(name.clone(), type_deduced.clone(), *identifier_span, true); + self.env.add( + name.to_string(), + type_deduced.clone(), + *identifier_span, + true, + ); } typed_ast::Statement::DefineDerivedUnit( - identifier.clone(), + identifier.to_string(), expr_checked, decorators.clone(), type_annotation.clone(), @@ -1328,7 +1341,7 @@ impl TypeChecker { if body.is_none() { self.value_namespace .add_identifier( - function_name.clone(), + function_name.to_string(), *function_name_span, "foreign function".to_owned(), ) @@ -1336,7 +1349,7 @@ impl TypeChecker { } else { self.value_namespace .add_identifier_allow_override( - function_name.clone(), + function_name.to_string(), *function_name_span, "function".to_owned(), ) @@ -1355,23 +1368,27 @@ impl TypeChecker { if self.type_namespace.has_identifier(type_parameter) { return Err(Box::new(TypeCheckError::TypeParameterNameClash( *span, - type_parameter.clone(), + type_parameter.to_string(), ))); } self.type_namespace - .add_identifier(type_parameter.clone(), *span, "type parameter".to_owned()) + .add_identifier( + type_parameter.to_string(), + *span, + "type parameter".to_owned(), + ) .ok(); // TODO: is this call even correct? self.registry.introduced_type_parameters.push(( *span, - type_parameter.clone(), + type_parameter.to_string(), bound.clone(), )); match bound { Some(TypeParameterBound::Dim) => { - self.add_dtype_constraint(&Type::TPar(type_parameter.clone())) + self.add_dtype_constraint(&Type::TPar(type_parameter.to_string())) .ok(); } None => {} @@ -1394,20 +1411,20 @@ impl TypeChecker { return Err(Box::new( TypeCheckError::ForeignFunctionNeedsTypeAnnotations( *parameter_span, - parameter.clone(), + parameter.to_string(), ), )); } self.env.add_scheme( - parameter.clone(), + parameter.to_string(), TypeScheme::make_quantified(parameter_type.clone()), *parameter_span, false, ); typed_parameters.push(( *parameter_span, - parameter.clone(), + parameter.to_string(), parameter_type, type_annotation, )); @@ -1438,18 +1455,21 @@ impl TypeChecker { TypeScheme::Concrete(Type::Fn(parameter_types, Box::new(return_type.clone()))); self.env.add_function( - function_name.clone(), + function_name.to_string(), FunctionSignature { - name: function_name.clone(), + name: function_name.to_string(), definition_span: *function_name_span, - type_parameters: type_parameters.clone(), + type_parameters: type_parameters + .iter() + .map(|(span, name, tpb)| (*span, name.to_string(), tpb.clone()).clone()) + .collect(), parameters, return_type_annotation: return_type_annotation.clone(), fn_type: fn_type.clone(), }, FunctionMetadata { - name: crate::decorator::name(decorators), - url: crate::decorator::url(decorators), + name: crate::decorator::name(decorators).map(ToOwned::to_owned), + url: crate::decorator::url(decorators).map(ToOwned::to_owned), description: crate::decorator::description(decorators), }, ); @@ -1524,17 +1544,17 @@ impl TypeChecker { } return_type_inferred } else { - if !ffi::functions().contains_key(function_name.as_str()) { + if !ffi::functions().contains_key(*function_name) { return Err(Box::new(TypeCheckError::UnknownForeignFunction( *function_name_span, - function_name.clone(), + function_name.to_string(), ))); } annotated_return_type.ok_or_else(|| { TypeCheckError::ForeignFunctionNeedsTypeAnnotations( *function_name_span, - function_name.clone(), + function_name.to_string(), ) })? }; @@ -1552,19 +1572,22 @@ impl TypeChecker { self.value_namespace.restore(); self.type_namespace.restore(); self.env.restore(); - self.env - .add_function(function_name.clone(), signature.clone(), metadata.clone()); + self.env.add_function( + function_name.to_string(), + signature.clone(), + metadata.clone(), + ); typed_ast::Statement::DefineFunction( - function_name.clone(), + function_name.to_string(), decorators.clone(), type_parameters .iter() - .map(|(_, name, bound)| (name.clone(), bound.clone())) + .map(|(_, name, bound)| (name.to_string(), bound.clone())) .collect(), typed_parameters .iter() - .map(|(span, name, _, ref type_annotation)| { + .map(|(span, name, _, type_annotation)| { ( *span, name.clone(), @@ -1582,7 +1605,7 @@ impl TypeChecker { } ast::Statement::DefineDimension(name_span, name, dexprs) => { self.type_namespace - .add_identifier(name.clone(), *name_span, "dimension".to_owned()) + .add_identifier(name.to_string(), *name_span, "dimension".to_owned()) .map_err(|err| Box::new(err.into()))?; if let Some(dexpr) = dexprs.first() { @@ -1603,7 +1626,7 @@ impl TypeChecker { if alternative_base_representation != base_representation { return Err(Box::new( TypeCheckError::IncompatibleAlternativeDimensionExpression( - name.clone(), + name.to_string(), dexpr.full_span(), base_representation, alternative_expr.full_span(), @@ -1617,7 +1640,7 @@ impl TypeChecker { .add_base_dimension(name) .map_err(TypeCheckError::RegistryError)?; } - typed_ast::Statement::DefineDimension(name.clone(), dexprs.clone()) + typed_ast::Statement::DefineDimension(name.to_string(), dexprs.clone()) } ast::Statement::ProcedureCall(span, kind @ ProcedureKind::Type, args) => { if args.len() != 1 { @@ -1715,7 +1738,11 @@ impl TypeChecker { fields, } => { self.type_namespace - .add_identifier(struct_name.clone(), *struct_name_span, "struct".to_owned()) + .add_identifier( + struct_name.to_string(), + *struct_name_span, + "struct".to_owned(), + ) .map_err(|err| Box::new(err.into()))?; let mut seen_fields = HashMap::new(); @@ -1734,23 +1761,26 @@ impl TypeChecker { let struct_info = StructInfo { definition_span: *struct_name_span, - name: struct_name.clone(), + name: struct_name.to_string(), fields: fields .iter() .map(|(span, name, type_)| { - Ok((name.clone(), (*span, self.type_from_annotation(type_)?))) + Ok((name.to_string(), (*span, self.type_from_annotation(type_)?))) }) .collect::>()?, }; self.structs - .insert(struct_name.clone(), struct_info.clone()); + .insert(struct_name.to_string(), struct_info.clone()); typed_ast::Statement::DefineStruct(struct_info) } }) } - fn check_statement(&mut self, statement: &ast::Statement) -> Result { + fn check_statement<'a>( + &mut self, + statement: &ast::Statement<'a>, + ) -> Result> { self.constraints.clear(); self.registry.introduced_type_parameters.clear(); @@ -1862,10 +1892,10 @@ impl TypeChecker { Ok(elaborated_statement) } - pub fn check( + pub fn check<'a>( &mut self, - statements: impl IntoIterator, - ) -> Result> { + statements: impl IntoIterator>, + ) -> Result>> { let mut checked_statements = vec![]; for statement in statements.into_iter() { diff --git a/numbat/src/typechecker/substitutions.rs b/numbat/src/typechecker/substitutions.rs index fd84b83d..400e4a29 100644 --- a/numbat/src/typechecker/substitutions.rs +++ b/numbat/src/typechecker/substitutions.rs @@ -210,7 +210,7 @@ impl ApplySubstitution for Expression { } } -impl ApplySubstitution for Statement { +impl ApplySubstitution for Statement<'_> { fn apply(&mut self, s: &Substitution) -> Result<(), SubstitutionError> { match self { Statement::Expression(e) => e.apply(s), diff --git a/numbat/src/typechecker/tests/mod.rs b/numbat/src/typechecker/tests/mod.rs index d38b3108..7d6014c0 100644 --- a/numbat/src/typechecker/tests/mod.rs +++ b/numbat/src/typechecker/tests/mod.rs @@ -49,9 +49,12 @@ fn type_c() -> DType { DType::base_dimension("A").multiply(&DType::base_dimension("B")) } -fn run_typecheck(input: &str) -> Result { - let code = &format!("{TEST_PRELUDE}\n{input}"); - let statements = parse(code, 0).expect("No parse errors for inputs in this test suite"); +fn run_typecheck(input: &str) -> Result> { + let statements = parse(TEST_PRELUDE, 0) + .expect("No parse errors for inputs in this test suite") + .into_iter() + .chain(parse(input, 0).expect("No parse errors for inputs in this test suite")); + let transformed_statements = Transformer::new() .transform(statements) .map_err(|err| Box::new(err.into()))?; diff --git a/numbat/src/typechecker/type_scheme.rs b/numbat/src/typechecker/type_scheme.rs index 1be2d451..246b50b4 100644 --- a/numbat/src/typechecker/type_scheme.rs +++ b/numbat/src/typechecker/type_scheme.rs @@ -40,9 +40,9 @@ impl TypeScheme { } } - pub fn instantiate_for_printing( + pub fn instantiate_for_printing<'a, I: Iterator + ExactSizeIterator>( &self, - type_parameters: Option>, + type_parameters: Option, ) -> (QualifiedType, Vec) { match self { TypeScheme::Concrete(t) => { @@ -53,9 +53,7 @@ impl TypeScheme { TypeScheme::Quantified(n_gen, _) => { // TODO: is this a good idea? we don't take care of name clashes here let type_parameters = match type_parameters { - Some(tp) if tp.len() == *n_gen => { - tp.iter().map(|s| TypeVariable::new(s.clone())).collect() - } + Some(tp) if tp.len() == *n_gen => tp.map(TypeVariable::new).collect(), _ => { if *n_gen <= 26 { (0..*n_gen) @@ -111,7 +109,8 @@ impl TypeScheme { registry: &crate::dimension::DimensionRegistry, with_quantifiers: bool, ) -> crate::markup::Markup { - let (instantiated_type, type_parameters) = self.instantiate_for_printing(None); + let (instantiated_type, type_parameters) = + self.instantiate_for_printing::< as IntoIterator>::IntoIter>(None); let mut markup = m::empty(); diff --git a/numbat/src/typed_ast.rs b/numbat/src/typed_ast.rs index ececa174..44c65cf8 100644 --- a/numbat/src/typed_ast.rs +++ b/numbat/src/typed_ast.rs @@ -36,14 +36,16 @@ impl DTypeFactor { } } +type DtypeFactorPower = (DTypeFactor, Exponent); + #[derive(Clone, Debug, PartialEq, Eq)] pub struct DType { // Always in canonical form - pub factors: Vec<(DTypeFactor, Exponent)>, // TODO make this private + pub factors: Vec, // TODO make this private } impl DType { - pub fn from_factors(factors: &[(DTypeFactor, Exponent)]) -> DType { + pub fn from_factors(factors: &[DtypeFactorPower]) -> DType { let mut dtype = DType { factors: factors.into(), }; @@ -201,9 +203,7 @@ impl DType { .contains(name) } - pub fn split_first_factor( - &self, - ) -> Option<(&(DTypeFactor, Exponent), &[(DTypeFactor, Exponent)])> { + pub fn split_first_factor(&self) -> Option<(&DtypeFactorPower, &[DtypeFactorPower])> { self.factors.split_first() } @@ -569,9 +569,9 @@ impl Expression { } #[derive(Debug, Clone, PartialEq)] -pub struct DefineVariable( +pub struct DefineVariable<'a>( pub String, - pub Vec, + pub Vec>, pub Expression, pub Option, pub TypeScheme, @@ -579,12 +579,12 @@ pub struct DefineVariable( ); #[derive(Debug, Clone, PartialEq)] -pub enum Statement { +pub enum Statement<'a> { Expression(Expression), - DefineVariable(DefineVariable), + DefineVariable(DefineVariable<'a>), DefineFunction( String, - Vec, // decorators + Vec>, // decorators Vec<(String, Option)>, // type parameters Vec<( // parameters: @@ -593,18 +593,23 @@ pub enum Statement { Option, // parameter type annotation Markup, // readable parameter type )>, - Option, // function body - Vec, // local variables - TypeScheme, // function type - Option, // return type annotation - Markup, // readable return type + Option, // function body + Vec>, // local variables + TypeScheme, // function type + Option, // return type annotation + Markup, // readable return type ), DefineDimension(String, Vec), - DefineBaseUnit(String, Vec, Option, TypeScheme), + DefineBaseUnit( + String, + Vec>, + Option, + TypeScheme, + ), DefineDerivedUnit( String, Expression, - Vec, + Vec>, Option, TypeScheme, Markup, @@ -613,7 +618,7 @@ pub enum Statement { DefineStruct(StructInfo), } -impl Statement { +impl Statement<'_> { pub fn as_expression(&self) -> Option<&Expression> { if let Self::Expression(v) = self { Some(v) @@ -664,7 +669,7 @@ impl Statement { readable_return_type, ) => { let (fn_type, _) = fn_type.instantiate_for_printing(Some( - type_parameters.iter().map(|(n, _)| n.clone()).collect(), + type_parameters.iter().map(|(n, _)| n.as_str()), )); for DefineVariable(_, _, _, type_annotation, type_, readable_type) in @@ -867,14 +872,14 @@ fn decorator_markup(decorators: &Vec) -> Markup { markup_decorators } -pub fn pretty_print_function_signature( +pub fn pretty_print_function_signature<'a>( function_name: &str, fn_type: &QualifiedType, type_parameters: &[TypeVariable], parameters: impl Iterator< Item = ( - String, // parameter name - Markup, // readable parameter type + &'a str, // parameter name + Markup, // readable parameter type ), >, readable_return_type: &Markup, @@ -919,7 +924,7 @@ pub fn pretty_print_function_signature( + markup_return_type } -impl PrettyPrint for Statement { +impl PrettyPrint for Statement<'_> { fn pretty_print(&self) -> Markup { match self { Statement::DefineVariable(DefineVariable( @@ -953,7 +958,7 @@ impl PrettyPrint for Statement { readable_return_type, ) => { let (fn_type, type_parameters) = fn_type.instantiate_for_printing(Some( - type_parameters.iter().map(|(n, _)| n.clone()).collect(), + type_parameters.iter().map(|(n, _)| n.as_str()), )); let mut pretty_local_variables = None; @@ -997,7 +1002,7 @@ impl PrettyPrint for Statement { &type_parameters, parameters .iter() - .map(|(_, name, _, type_)| (name.clone(), type_.clone())), + .map(|(_, name, _, type_)| (name.as_str(), type_.clone())), readable_return_type, ) + body .as_ref() @@ -1341,8 +1346,7 @@ mod tests { fn parse(code: &str) -> Statement { let statements = crate::parser::parse( - &format!( - "dimension Scalar = 1 + "dimension Scalar = 1 dimension Length dimension Time dimension Mass @@ -1380,7 +1384,7 @@ mod tests { @metric_prefixes unit points - struct Foo {{foo: Length, bar: Time}} + struct Foo {foo: Length, bar: Time} let a = 1 let b = 1 @@ -1395,13 +1399,12 @@ mod tests { let länge = 1 let x_2 = 1 let µ = 1 - let _prefixed = 1 - - {code}" - ), + let _prefixed = 1", 0, ) - .unwrap(); + .unwrap() + .into_iter() + .chain(crate::parser::parse(code, 0).unwrap()); let mut transformer = Transformer::new(); let transformed_statements = transformer.transform(statements).unwrap().replace_spans();