From 37e70062b516b8aae7ffeb8e9fb9df007e3085ee Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Mon, 5 Jun 2023 11:11:07 +0200 Subject: [PATCH] Allocate literals during hir lowering --- crates/rune/src/ast/lit_str.rs | 11 +- crates/rune/src/ast/spanned.rs | 4 +- crates/rune/src/ast/token.rs | 5 - crates/rune/src/compile/error.rs | 2 - crates/rune/src/compile/ir.rs | 11 +- crates/rune/src/compile/ir/compiler.rs | 65 ++----- crates/rune/src/compile/ir/eval.rs | 2 +- crates/rune/src/compile/ir/value.rs | 24 +-- crates/rune/src/compile/v1/assemble.rs | 229 +++++-------------------- crates/rune/src/hir/arena.rs | 90 ++++++++-- crates/rune/src/hir/hir.rs | 125 ++++++++------ crates/rune/src/hir/lowering.rs | 152 ++++++++++++++-- crates/rune/src/indexing/index.rs | 11 +- crates/rune/src/query.rs | 4 +- 14 files changed, 367 insertions(+), 368 deletions(-) diff --git a/crates/rune/src/ast/lit_str.rs b/crates/rune/src/ast/lit_str.rs index 732a32541..d406cd59b 100644 --- a/crates/rune/src/ast/lit_str.rs +++ b/crates/rune/src/ast/lit_str.rs @@ -30,11 +30,16 @@ impl LitStr { &self, ctx: ResolveContext<'a>, ) -> Result> { - self.resolve_string(ctx, ast::utils::WithTemplate(true)) + self.resolve_inner(ctx, ast::utils::WithTemplate(true)) + } + + /// Resolve as a regular string. + pub(crate) fn resolve_string<'a>(&self, ctx: ResolveContext<'a>) -> Result> { + self.resolve_inner(ctx, ast::utils::WithTemplate(false)) } /// Resolve the given string with the specified configuration. - pub(crate) fn resolve_string<'a>( + fn resolve_inner<'a>( &self, ctx: ResolveContext<'a>, with_template: ast::utils::WithTemplate, @@ -132,7 +137,7 @@ impl<'a> Resolve<'a> for LitStr { type Output = Cow<'a, str>; fn resolve(&self, ctx: ResolveContext<'a>) -> Result> { - self.resolve_string(ctx, ast::utils::WithTemplate(false)) + self.resolve_string(ctx) } } diff --git a/crates/rune/src/ast/spanned.rs b/crates/rune/src/ast/spanned.rs index c012e36c1..56a32630e 100644 --- a/crates/rune/src/ast/spanned.rs +++ b/crates/rune/src/ast/spanned.rs @@ -45,7 +45,7 @@ where impl Spanned for &T where - T: Spanned, + T: ?Sized + Spanned, { fn span(&self) -> Span { Spanned::span(*self) @@ -54,7 +54,7 @@ where impl Spanned for &mut T where - T: Spanned, + T: ?Sized + Spanned, { fn span(&self) -> Span { Spanned::span(*self) diff --git a/crates/rune/src/ast/token.rs b/crates/rune/src/ast/token.rs index 1c56a76f4..92dad7c3d 100644 --- a/crates/rune/src/ast/token.rs +++ b/crates/rune/src/ast/token.rs @@ -178,11 +178,6 @@ impl Number { self.as_primitive(neg, num::ToPrimitive::to_u32) } - /// Convert into a 64-bit signed number. - pub(crate) fn as_i64(&self, neg: bool) -> Result { - self.as_primitive(neg, num::ToPrimitive::to_i64) - } - /// Convert into usize. pub(crate) fn as_usize(&self, neg: bool) -> Result { self.as_primitive(neg, num::ToPrimitive::to_usize) diff --git a/crates/rune/src/compile/error.rs b/crates/rune/src/compile/error.rs index bfdc26b00..555203bc2 100644 --- a/crates/rune/src/compile/error.rs +++ b/crates/rune/src/compile/error.rs @@ -597,8 +597,6 @@ pub(crate) enum IrErrorKind { FnNotFound, #[error("Argument count mismatch, got {actual} but expected {expected}")] ArgumentCountMismatch { actual: usize, expected: usize }, - #[error("Value `{value}` is outside of the supported integer range")] - NotInteger { value: num::BigInt }, } /// The kind of a hir error. diff --git a/crates/rune/src/compile/ir.rs b/crates/rune/src/compile/ir.rs index 3cdc2d4cb..c7735be24 100644 --- a/crates/rune/src/compile/ir.rs +++ b/crates/rune/src/compile/ir.rs @@ -312,7 +312,7 @@ pub struct IrBranches { /// The condition for a branch. #[derive(Debug, Clone, Spanned)] pub enum IrCondition { - /// A simple conditiona ir expression. + /// A simple conditional ir expression. Ir(Ir), /// A pattern match. Let(IrLet), @@ -558,12 +558,7 @@ impl IrAssignOp { } /// Perform the given assign operation. - fn assign_int( - self, - spanned: S, - target: &mut num::BigInt, - operand: num::BigInt, - ) -> compile::Result<()> + fn assign_int(self, spanned: S, target: &mut i64, operand: i64) -> compile::Result<()> where S: Copy + Spanned, { @@ -579,7 +574,7 @@ impl IrAssignOp { } IrAssignOp::Div => { *target = target - .checked_div(&operand) + .checked_div(operand) .ok_or("division by zero") .with_span(spanned)?; } diff --git a/crates/rune/src/compile/ir/compiler.rs b/crates/rune/src/compile/ir/compiler.rs index f19b30b49..f563b7986 100644 --- a/crates/rune/src/compile/ir/compiler.rs +++ b/crates/rune/src/compile/ir/compiler.rs @@ -90,7 +90,7 @@ pub(crate) fn expr(hir: &hir::Expr<'_>, c: &mut IrCompiler<'_>) -> compile::Resu hir::ExprKind::Call(hir) => ir::Ir::new(span, expr_call(span, c, hir)?), hir::ExprKind::If(hir) => ir::Ir::new(span, expr_if(span, c, hir)?), hir::ExprKind::Loop(hir) => ir::Ir::new(span, expr_loop(span, c, hir)?), - hir::ExprKind::Lit(hir) => lit(hir, c)?, + hir::ExprKind::Lit(hir) => lit(span, c, hir)?, hir::ExprKind::Block(hir) => expr_block(span, c, hir)?, hir::ExprKind::Path(hir) => path(hir, c)?, hir::ExprKind::FieldAccess(..) => ir::Ir::new(span, c.ir_target(hir)?), @@ -100,20 +100,8 @@ pub(crate) fn expr(hir: &hir::Expr<'_>, c: &mut IrCompiler<'_>) -> compile::Resu let ir_template = builtin_template(template, c)?; ir::Ir::new(hir.span(), ir_template) } - hir::MacroCall::File(file) => { - let s = c.resolve(&file.value)?; - ir::Ir::new(file.span, IrValue::String(Shared::new(s.into_owned()))) - } - hir::MacroCall::Line(line) => { - let n = c.resolve(&line.value)?; - - let const_value = match n { - ast::Number::Integer(n) => IrValue::Integer(n), - ast::Number::Float(n) => IrValue::Float(n), - }; - - ir::Ir::new(line.span, const_value) - } + hir::MacroCall::File(file) => lit(span, c, file.value)?, + hir::MacroCall::Line(line) => lit(span, c, line.value)?, _ => { return Err(compile::Error::msg(hir, "unsupported builtin macro")); } @@ -227,38 +215,18 @@ fn expr_binary( } #[instrument] -fn lit(hir: &ast::Lit, c: &mut IrCompiler<'_>) -> compile::Result { - let span = hir.span(); - +fn lit(span: Span, c: &mut IrCompiler<'_>, hir: hir::Lit<'_>) -> compile::Result { Ok(match hir { - ast::Lit::Bool(b) => ir::Ir::new(span, IrValue::Bool(b.value)), - ast::Lit::Str(s) => { - let s = c.resolve(s)?; - ir::Ir::new(span, IrValue::String(Shared::new(s.into_owned()))) - } - ast::Lit::Number(n) => { - let n = c.resolve(n)?; - - let const_value = match n { - ast::Number::Integer(n) => IrValue::Integer(n), - ast::Number::Float(n) => IrValue::Float(n), - }; - - ir::Ir::new(span, const_value) - } - ast::Lit::Byte(lit) => { - let b = c.resolve(lit)?; - ir::Ir::new(span, IrValue::Byte(b)) - } - ast::Lit::ByteStr(lit) => { - let byte_str = c.resolve(lit)?; - let value = IrValue::Bytes(Shared::new(Bytes::from_vec(byte_str.into_owned()))); + hir::Lit::Bool(boolean) => ir::Ir::new(span, IrValue::Bool(boolean)), + hir::Lit::Str(string) => ir::Ir::new(span, IrValue::String(Shared::new(string.to_owned()))), + hir::Lit::Integer(n) => ir::Ir::new(span, IrValue::Integer(n)), + hir::Lit::Float(n) => ir::Ir::new(span, IrValue::Float(n)), + hir::Lit::Byte(b) => ir::Ir::new(span, IrValue::Byte(b)), + hir::Lit::ByteStr(byte_str) => { + let value = IrValue::Bytes(Shared::new(Bytes::from_vec(byte_str.to_vec()))); ir::Ir::new(span, value) } - ast::Lit::Char(lit) => { - let c = c.resolve(lit)?; - ir::Ir::new(span, IrValue::Char(c)) - } + hir::Lit::Char(c) => ir::Ir::new(span, IrValue::Char(c)), }) } @@ -400,13 +368,8 @@ fn builtin_template( let mut components = Vec::new(); for e in template.exprs { - if let hir::ExprKind::Lit(ast::Lit::Str(s)) = e.kind { - let s = s.resolve_template_string(resolve_context!(c.q))?; - - components.push(ir::IrTemplateComponent::String( - s.into_owned().into_boxed_str(), - )); - + if let hir::ExprKind::Lit(hir::Lit::Str(s)) = e.kind { + components.push(ir::IrTemplateComponent::String(s.into())); continue; } diff --git a/crates/rune/src/compile/ir/eval.rs b/crates/rune/src/compile/ir/eval.rs index 4d9c35659..58f592844 100644 --- a/crates/rune/src/compile/ir/eval.rs +++ b/crates/rune/src/compile/ir/eval.rs @@ -96,7 +96,7 @@ fn eval_ir_binary( } ir::IrBinaryOp::Div => { let number = a - .checked_div(&b) + .checked_div(b) .ok_or_else(|| compile::Error::msg(span, "division by zero"))?; return Ok(IrValue::Integer(number)); } diff --git a/crates/rune/src/compile/ir/value.rs b/crates/rune/src/compile/ir/value.rs index 0743fb425..a19a45cf0 100644 --- a/crates/rune/src/compile/ir/value.rs +++ b/crates/rune/src/compile/ir/value.rs @@ -2,7 +2,7 @@ use crate::no_std::collections::HashMap; use crate::no_std::prelude::*; use crate::ast::Spanned; -use crate::compile::{self, IrErrorKind, WithSpan}; +use crate::compile::{self, WithSpan}; use crate::runtime as rt; use crate::runtime::{Bytes, ConstValue, Shared, TypeInfo}; @@ -18,7 +18,7 @@ pub enum IrValue { /// A boolean constant value. Bool(bool), /// An integer constant. - Integer(num::BigInt), + Integer(i64), /// An float constant. Float(f64), /// A string constant designated by its slot. @@ -47,7 +47,7 @@ impl IrValue { /// Try to coerce into an integer of the specified type. pub fn into_integer(self) -> Option where - T: TryFrom, + T: TryFrom, { match self { Self::Integer(n) => T::try_from(n).ok(), @@ -62,7 +62,7 @@ impl IrValue { ConstValue::Byte(b) => Self::Byte(*b), ConstValue::Char(c) => Self::Char(*c), ConstValue::Bool(b) => Self::Bool(*b), - ConstValue::Integer(n) => Self::Integer((*n).into()), + ConstValue::Integer(n) => Self::Integer(*n), ConstValue::Float(n) => Self::Float(*n), ConstValue::String(s) => Self::String(Shared::new(s.clone())), ConstValue::StaticString(s) => Self::String(Shared::new((***s).to_owned())), @@ -105,26 +105,12 @@ impl IrValue { where S: Copy + Spanned, { - use num::ToPrimitive as _; - Ok(match self { IrValue::Unit => ConstValue::Unit, IrValue::Byte(b) => ConstValue::Byte(b), IrValue::Char(c) => ConstValue::Char(c), IrValue::Bool(b) => ConstValue::Bool(b), - IrValue::Integer(n) => { - let n = match n.clone().to_i64() { - Some(n) => n, - None => { - return Err(compile::Error::new( - spanned, - IrErrorKind::NotInteger { value: n }, - )) - } - }; - - ConstValue::Integer(n) - } + IrValue::Integer(n) => ConstValue::Integer(n), IrValue::Float(f) => ConstValue::Float(f), IrValue::String(s) => { let s = s.take().with_span(spanned)?; diff --git a/crates/rune/src/compile/v1/assemble.rs b/crates/rune/src/compile/v1/assemble.rs index 1ddf69b05..3f06019b6 100644 --- a/crates/rune/src/compile/v1/assemble.rs +++ b/crates/rune/src/compile/v1/assemble.rs @@ -1,15 +1,12 @@ use core::mem::{replace, take}; -use core::ops::Neg; use crate::no_std::collections::{HashMap, HashSet}; use crate::no_std::prelude::*; -use num::ToPrimitive; - use crate::ast::{self, Span, Spanned}; use crate::compile::meta; use crate::compile::v1::{Assembler, GenericsParameters, Loop, Needs, Scope, Var}; -use crate::compile::{self, CompileErrorKind, Item, ParseErrorKind, WithSpan}; +use crate::compile::{self, CompileErrorKind, Item, WithSpan}; use crate::hash::ParametersBuilder; use crate::hir; use crate::parse::{Id, Resolve}; @@ -61,11 +58,8 @@ pub(crate) enum AsmKind { impl Asm { /// Assemble into an instruction. fn apply(self, c: &mut Assembler) -> compile::Result<()> { - match self.kind { - AsmKind::Top => (), - AsmKind::Var(var, local) => { - var.copy(c, self.span, format_args!("var `{}`", local)); - } + if let AsmKind::Var(var, local) = self.kind { + var.copy(c, self.span, format_args!("var `{}`", local)); } Ok(()) @@ -324,14 +318,11 @@ fn pat_lit( ) -> compile::Result { let span = hir.span(); - let inst = match pat_lit_inst(span, c, hir)? { - Some(inst) => inst, - None => { - return Err(compile::Error::new( - hir, - CompileErrorKind::UnsupportedPatternExpr, - )); - } + let Some(inst) = pat_lit_inst(span, c, hir)? else { + return Err(compile::Error::new( + hir, + CompileErrorKind::UnsupportedPatternExpr, + )); }; load(c, Needs::Value)?; @@ -347,58 +338,25 @@ fn pat_lit_inst( c: &mut Assembler<'_>, hir: &hir::Expr<'_>, ) -> compile::Result> { - match hir.kind { - hir::ExprKind::Unary(hir::ExprUnary { - op: ast::UnOp::Neg(..), - expr: - hir::Expr { - kind: hir::ExprKind::Lit(ast::Lit::Number(lit)), - .. - }, - .. - }) => { - let integer = lit - .resolve(resolve_context!(c.q))? - .as_i64(true) - .with_span(span)?; - - return Ok(Some(Inst::EqInteger { integer })); - } - hir::ExprKind::Lit(lit) => match lit { - ast::Lit::Byte(lit) => { - let byte = lit.resolve(resolve_context!(c.q))?; - return Ok(Some(Inst::EqByte { byte })); - } - ast::Lit::Char(lit) => { - let char = lit.resolve(resolve_context!(c.q))?; - return Ok(Some(Inst::EqChar { char })); - } - ast::Lit::Str(lit) => { - let string = lit.resolve(resolve_context!(c.q))?; - let slot = c.q.unit.new_static_string(span, string.as_ref())?; - return Ok(Some(Inst::EqString { slot })); - } - ast::Lit::ByteStr(lit) => { - let bytes = lit.resolve(resolve_context!(c.q))?; - let slot = c.q.unit.new_static_bytes(span, bytes.as_ref())?; - return Ok(Some(Inst::EqBytes { slot })); - } - ast::Lit::Number(lit) => { - let integer = lit - .resolve(resolve_context!(c.q))? - .as_i64(false) - .with_span(lit)?; + let hir::ExprKind::Lit(lit) = hir.kind else { + return Ok(None); + }; - return Ok(Some(Inst::EqInteger { integer })); - } - ast::Lit::Bool(lit) => { - return Ok(Some(Inst::EqBool { boolean: lit.value })); - } + let inst = match lit { + hir::Lit::Byte(byte) => Inst::EqByte { byte }, + hir::Lit::Char(char) => Inst::EqChar { char }, + hir::Lit::Str(string) => Inst::EqString { + slot: c.q.unit.new_static_string(span, string)?, }, - _ => (), - } + hir::Lit::ByteStr(bytes) => Inst::EqBytes { + slot: c.q.unit.new_static_bytes(span, bytes)?, + }, + hir::Lit::Integer(integer) => Inst::EqInteger { integer }, + hir::Lit::Bool(boolean) => Inst::EqBool { boolean }, + _ => return Ok(None), + }; - Ok(None) + Ok(Some(inst)) } /// Assemble an [hir::Condition<'_>]. @@ -1022,11 +980,9 @@ fn builtin_template( let mut expansions = 0; for hir in template.exprs { - if let hir::ExprKind::Lit(ast::Lit::Str(s)) = hir.kind { - let s = s.resolve_template_string(resolve_context!(c.q))?; + if let hir::ExprKind::Lit(hir::Lit::Str(s)) = hir.kind { size_hint += s.len(); - - let slot = c.q.unit.new_static_string(span, &s)?; + let slot = c.q.unit.new_static_string(span, s)?; c.asm.push(Inst::String { slot }, span); c.scopes.decl_anon(span)?; continue; @@ -1083,17 +1039,7 @@ fn const_( c.asm.push(Inst::char(*ch), span); } ConstValue::Integer(n) => { - let n = match n.to_i64() { - Some(n) => n, - None => { - return Err(compile::Error::new( - span, - ParseErrorKind::BadNumberOutOfBounds, - )); - } - }; - - c.asm.push(Inst::integer(n), span); + c.asm.push(Inst::integer(*n), span); } ConstValue::Float(n) => { c.asm.push(Inst::float(*n), span); @@ -1193,7 +1139,7 @@ fn expr(hir: &hir::Expr<'_>, c: &mut Assembler<'_>, needs: Needs) -> compile::Re hir::ExprKind::Call(hir) => expr_call(span, c, hir, needs)?, hir::ExprKind::FieldAccess(hir) => expr_field_access(span, c, hir, needs)?, hir::ExprKind::Closure(hir) => expr_closure(span, c, hir, needs)?, - hir::ExprKind::Lit(hir) => lit(hir, c, needs)?, + hir::ExprKind::Lit(hir) => lit(span, c, hir, needs)?, hir::ExprKind::Tuple(hir) => expr_tuple(span, c, hir, needs)?, hir::ExprKind::Vec(hir) => expr_vec(span, c, hir, needs)?, hir::ExprKind::Object(hir) => expr_object(span, c, hir, needs)?, @@ -1201,8 +1147,8 @@ fn expr(hir: &hir::Expr<'_>, c: &mut Assembler<'_>, needs: Needs) -> compile::Re hir::ExprKind::MacroCall(macro_call) => match macro_call { hir::MacroCall::Template(template) => builtin_template(template, c, needs)?, hir::MacroCall::Format(format) => builtin_format(format, c, needs)?, - hir::MacroCall::Line(line) => lit_number(&line.value, c, needs)?, - hir::MacroCall::File(file) => lit_str(&file.value, c, needs)?, + hir::MacroCall::Line(line) => lit(line.span, c, line.value, needs)?, + hir::MacroCall::File(file) => lit(file.span, c, file.value, needs)?, }, }; @@ -3120,34 +3066,6 @@ fn expr_unary( hir: &hir::ExprUnary<'_>, needs: Needs, ) -> compile::Result { - // NB: special unary expressions. - if let ast::UnOp::BorrowRef { .. } = hir.op { - return Err(compile::Error::new(span, CompileErrorKind::UnsupportedRef)); - } - - if let (ast::UnOp::Neg(..), hir::ExprKind::Lit(ast::Lit::Number(n))) = (hir.op, hir.expr.kind) { - match n.resolve(resolve_context!(c.q))? { - ast::Number::Float(n) => { - c.asm.push(Inst::float(-n), span); - } - ast::Number::Integer(int) => { - let n = match int.neg().to_i64() { - Some(n) => n, - None => { - return Err(compile::Error::new( - span, - ParseErrorKind::BadNumberOutOfBounds, - )); - } - }; - - c.asm.push(Inst::integer(n), span); - } - } - - return Ok(Asm::top(span)); - } - expr(hir.expr, c, Needs::Value)?.apply(c)?; match hir.op { @@ -3340,9 +3258,7 @@ pub(crate) fn fn_from_item_fn( /// Assemble a literal value. #[instrument] -fn lit(hir: &ast::Lit, c: &mut Assembler<'_>, needs: Needs) -> compile::Result { - let span = hir.span(); - +fn lit(span: Span, c: &mut Assembler<'_>, hir: hir::Lit<'_>, needs: Needs) -> compile::Result { // Elide the entire literal if it's not needed. if !needs.value() { c.diagnostics.not_used(c.source_id, span, c.context()); @@ -3350,26 +3266,27 @@ fn lit(hir: &ast::Lit, c: &mut Assembler<'_>, needs: Needs) -> compile::Result { - c.asm.push(Inst::bool(lit.value), span); + hir::Lit::Bool(boolean) => { + c.asm.push(Inst::bool(boolean), span); + } + hir::Lit::Byte(byte) => { + c.asm.push(Inst::byte(byte), span); } - ast::Lit::Number(lit) => { - return lit_number(lit, c, needs); + hir::Lit::Char(char) => { + c.asm.push(Inst::char(char), span); } - ast::Lit::Char(lit) => { - let ch = lit.resolve(resolve_context!(c.q))?; - c.asm.push(Inst::char(ch), span); + hir::Lit::Integer(integer) => { + c.asm.push(Inst::integer(integer), span); } - ast::Lit::Str(lit) => { - return lit_str(lit, c, needs); + hir::Lit::Float(float) => { + c.asm.push(Inst::float(float), span); } - ast::Lit::Byte(lit) => { - let b = lit.resolve(resolve_context!(c.q))?; - c.asm.push(Inst::byte(b), span); + hir::Lit::Str(string) => { + let slot = c.q.unit.new_static_string(span, string)?; + c.asm.push(Inst::String { slot }, span); } - ast::Lit::ByteStr(lit) => { - let bytes = lit.resolve(resolve_context!(c.q))?; - let slot = c.q.unit.new_static_bytes(span, bytes.as_ref())?; + hir::Lit::ByteStr(bytes) => { + let slot = c.q.unit.new_static_bytes(span, bytes)?; c.asm.push(Inst::Bytes { slot }, span); } }; @@ -3377,58 +3294,6 @@ fn lit(hir: &ast::Lit, c: &mut Assembler<'_>, needs: Needs) -> compile::Result, needs: Needs) -> compile::Result { - let span = hir.span(); - - // Elide the entire literal if it's not needed. - if !needs.value() { - c.diagnostics.not_used(c.source_id, span, c.context()); - return Ok(Asm::top(span)); - } - - let string = hir.resolve(resolve_context!(c.q))?; - let slot = c.q.unit.new_static_string(span, string.as_ref())?; - c.asm.push(Inst::String { slot }, span); - Ok(Asm::top(span)) -} - -/// Assemble a literal number. -#[instrument] -fn lit_number(hir: &ast::LitNumber, c: &mut Assembler<'_>, needs: Needs) -> compile::Result { - let span = hir.span(); - - // Elide the entire literal if it's not needed. - if !needs.value() { - c.diagnostics.not_used(c.source_id, span, c.context()); - return Ok(Asm::top(span)); - } - - // NB: don't encode unecessary literal. - let number = hir.resolve(resolve_context!(c.q))?; - - match number { - ast::Number::Float(number) => { - c.asm.push(Inst::float(number), span); - } - ast::Number::Integer(number) => { - let n = match number.to_i64() { - Some(n) => n, - None => { - return Err(compile::Error::new( - span, - ParseErrorKind::BadNumberOutOfBounds, - )); - } - }; - - c.asm.push(Inst::integer(n), span); - } - } - - Ok(Asm::top(span)) -} - /// Assemble a local expression. #[instrument] fn local(hir: &hir::Local<'_>, c: &mut Assembler<'_>, needs: Needs) -> compile::Result { diff --git a/crates/rune/src/hir/arena.rs b/crates/rune/src/hir/arena.rs index 3c7cb0e32..25200fc28 100644 --- a/crates/rune/src/hir/arena.rs +++ b/crates/rune/src/hir/arena.rs @@ -4,7 +4,9 @@ use core::marker::PhantomData; use core::mem; use core::ptr; use core::slice; +use core::str; +use crate::no_std::collections::HashMap; use crate::no_std::prelude::*; #[non_exhaustive] @@ -52,15 +54,55 @@ pub struct Arena { start: Cell<*mut u8>, end: Cell<*mut u8>, chunks: RefCell>, + /// Allocated bytes. The pointers are stable into the chunks. + bytes: RefCell, ptr::NonNull>>, } impl Arena { /// Construct a new empty arena allocator. - pub const fn new() -> Self { + pub fn new() -> Self { Self { start: Cell::new(ptr::null_mut()), end: Cell::new(ptr::null_mut()), chunks: RefCell::new(Vec::new()), + bytes: RefCell::new(HashMap::new()), + } + } + + /// Allocate a string from the arena. + pub(crate) fn alloc_bytes(&self, bytes: &[u8]) -> Result<&[u8], ArenaAllocError> { + if let Some(ptr) = self.bytes.borrow().get(bytes).copied() { + // SAFETY: The pointer returned was previously allocated correctly + // in the arena. + unsafe { + return Ok(slice::from_raw_parts(ptr.as_ptr() as *const _, bytes.len())); + } + } + + let layout = Layout::array::(bytes.len()).map_err(|_| ArenaAllocError { + requested: bytes.len(), + })?; + let ptr = self.alloc_raw(layout)?; + + // SAFETY: we're ensuring the valid contents of pointer by copying a + // safe bytes slice into it. + let output = unsafe { + ptr::copy_nonoverlapping(bytes.as_ptr(), ptr.as_ptr(), bytes.len()); + slice::from_raw_parts(ptr.as_ptr() as *const _, bytes.len()) + }; + + self.bytes.borrow_mut().insert(bytes.into(), ptr); + Ok(output) + } + + /// Allocate a string from the arena. + pub(crate) fn alloc_str(&self, string: &str) -> Result<&str, ArenaAllocError> { + let bytes = self.alloc_bytes(string.as_bytes())?; + + // SAFETY: we're ensuring the valid contents of the returned string by + // safely accessing it above. + unsafe { + return Ok(str::from_utf8_unchecked(bytes)); } } @@ -68,12 +110,12 @@ impl Arena { pub(crate) fn alloc(&self, object: T) -> Result<&mut T, ArenaAllocError> { assert!(!mem::needs_drop::()); - let mem = self.alloc_raw(Layout::for_value::(&object))? as *mut T; + let mut ptr = self.alloc_raw(Layout::for_value::(&object))?.cast(); unsafe { // Write into uninitialized memory. - ptr::write(mem, object); - Ok(&mut *mem) + ptr::write(ptr.as_ptr(), object); + Ok(ptr.as_mut()) } } @@ -82,9 +124,9 @@ impl Arena { assert!(!mem::needs_drop::(), "cannot allocate drop element"); let mem = if len == 0 { - ptr::null_mut() + None } else { - self.alloc_raw(Layout::array::(len).unwrap())? as *mut T + Some(self.alloc_raw(Layout::array::(len).unwrap())?.cast()) }; Ok(AllocIter { @@ -96,7 +138,7 @@ impl Arena { } #[inline] - fn alloc_raw_without_grow(&self, layout: Layout) -> Option<*mut u8> { + fn alloc_raw_without_grow(&self, layout: Layout) -> Option> { let start = addr(self.start.get()); let old_end = self.end.get(); let end = addr(old_end); @@ -112,12 +154,20 @@ impl Arena { let new_end = with_addr(old_end, new_end); self.end.set(new_end); - Some(new_end) + + // Pointer is guaranteed to be non-null due to how it's allocated. + unsafe { Some(ptr::NonNull::new_unchecked(new_end)) } } #[inline] - pub(crate) fn alloc_raw(&self, layout: Layout) -> Result<*mut u8, ArenaAllocError> { - assert!(layout.size() != 0); + fn alloc_raw(&self, layout: Layout) -> Result, ArenaAllocError> { + // assert!(layout.size() != 0); + assert!(layout.align() != 0); + + if layout.size() == 0 { + // SAFETY: we've asserted that alignment is non-zero above. + return unsafe { Ok(ptr::NonNull::new_unchecked(layout.align() as *mut u8)) }; + } loop { if let Some(a) = self.alloc_raw_without_grow(layout) { @@ -160,8 +210,8 @@ pub(crate) fn with_addr(this: *mut u8, a: usize) -> *mut u8 { } /// An iterator writer. -pub struct AllocIter<'hir, T> { - mem: *mut T, +pub(crate) struct AllocIter<'hir, T> { + mem: Option>, index: usize, len: usize, _marker: PhantomData<&'hir ()>, @@ -170,13 +220,17 @@ pub struct AllocIter<'hir, T> { impl<'hir, T> AllocIter<'hir, T> { /// Write the next element into the slice. pub(crate) fn write(&mut self, object: T) -> Result<(), ArenaWriteSliceOutOfBounds> { + let mem = self + .mem + .ok_or(ArenaWriteSliceOutOfBounds { index: self.index })?; + // Sanity check is necessary to ensure memory safety. if self.index >= self.len { return Err(ArenaWriteSliceOutOfBounds { index: self.index }); } unsafe { - ptr::write(self.mem.add(self.index), object); + ptr::write(mem.as_ptr().add(self.index), object); self.index += 1; Ok(()) } @@ -184,10 +238,12 @@ impl<'hir, T> AllocIter<'hir, T> { /// Finalize the iterator being written and return the appropriate closure. pub(crate) fn finish(self) -> &'hir mut [T] { - if self.mem.is_null() { - return &mut []; + match self.mem { + Some(mem) => { + // SAFETY: Is guaranteed to be correct due to how it's allocated and written to above. + unsafe { slice::from_raw_parts_mut(mem.as_ptr(), self.index) } + } + None => &mut [], } - - unsafe { slice::from_raw_parts_mut(self.mem, self.index) } } } diff --git a/crates/rune/src/hir/hir.rs b/crates/rune/src/hir/hir.rs index 5b110d7ca..a3c6299ed 100644 --- a/crates/rune/src/hir/hir.rs +++ b/crates/rune/src/hir/hir.rs @@ -9,7 +9,7 @@ use crate::parse::{Expectation, Id, IntoExpectation, Opaque, Resolve, ResolveCon use crate::runtime::format; /// Visibility level restricted to some path: pub(self) or pub(super) or pub or pub(in some::module). -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq)] #[non_exhaustive] pub enum Visibility<'hir> { /// An inherited visibility level, this usually means private. @@ -27,7 +27,7 @@ pub enum Visibility<'hir> { } /// A pattern. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, Clone, Copy, PartialEq, Spanned)] #[non_exhaustive] pub struct Pat<'hir> { /// The span of the pattern. @@ -38,7 +38,7 @@ pub struct Pat<'hir> { } /// The kind of a [Pat]. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum PatKind<'hir> { /// An ignored binding. PatIgnore, @@ -59,7 +59,7 @@ pub enum PatKind<'hir> { } /// A tuple pattern. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq)] #[non_exhaustive] pub struct PatItems<'hir> { /// The path, if the tuple is typed. @@ -73,7 +73,7 @@ pub struct PatItems<'hir> { } /// An object item. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq)] #[non_exhaustive] pub struct PatBinding<'hir> { /// The key of an object. @@ -83,7 +83,7 @@ pub struct PatBinding<'hir> { } /// An expression. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, Clone, Copy, PartialEq, Spanned)] #[non_exhaustive] pub struct Expr<'hir> { /// Span of the expression. @@ -93,8 +93,21 @@ pub struct Expr<'hir> { pub kind: ExprKind<'hir>, } +/// The kind of a number. +#[derive(Debug, Clone, Copy, PartialEq)] +#[non_exhaustive] +pub enum Lit<'hir> { + Bool(bool), + Integer(i64), + Float(f64), + Byte(u8), + Char(char), + Str(&'hir str), + ByteStr(&'hir [u8]), +} + /// The kind of an [Expr]. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq)] #[non_exhaustive] pub enum ExprKind<'hir> { Path(&'hir Path<'hir>), @@ -118,7 +131,7 @@ pub enum ExprKind<'hir> { Try(&'hir Expr<'hir>), Select(&'hir ExprSelect<'hir>), Closure(&'hir ExprClosure<'hir>), - Lit(&'hir ast::Lit), + Lit(Lit<'hir>), Object(&'hir ExprObject<'hir>), Tuple(&'hir ExprSeq<'hir>), Vec(&'hir ExprSeq<'hir>), @@ -131,7 +144,7 @@ pub enum ExprKind<'hir> { /// /// This is used to propagate information on built-in macros to the assembly /// phase of the compilation. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, Clone, Copy, PartialEq, Spanned)] #[non_exhaustive] pub enum MacroCall<'hir> { /// The built-in template macro. @@ -139,13 +152,13 @@ pub enum MacroCall<'hir> { /// The built-in format macro. Format(&'hir BuiltInFormat<'hir>), /// The built-in file! macro. - File(&'hir BuiltInFile), + File(&'hir BuiltInFile<'hir>), /// The built-in line! macro. - Line(&'hir BuiltInLine), + Line(&'hir BuiltInLine<'hir>), } /// An internally resolved template. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, Clone, Copy, PartialEq, Spanned)] pub struct BuiltInTemplate<'hir> { /// The span of the built-in template. #[rune(span)] @@ -157,7 +170,7 @@ pub struct BuiltInTemplate<'hir> { } /// An internal format specification. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, Clone, Copy, PartialEq, Spanned)] pub struct BuiltInFormat<'hir> { #[rune(span)] pub span: Span, @@ -178,27 +191,27 @@ pub struct BuiltInFormat<'hir> { } /// Macro data for `file!()` -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] -pub struct BuiltInFile { +#[derive(Debug, Clone, Copy, PartialEq, Spanned)] +pub struct BuiltInFile<'hir> { /// The span of the built-in-file #[rune(span)] pub span: Span, /// Path value to use - pub value: ast::LitStr, + pub value: Lit<'hir>, } /// Macro data for `line!()` -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] -pub struct BuiltInLine { +#[derive(Debug, Clone, Copy, PartialEq, Spanned)] +pub struct BuiltInLine<'hir> { /// The span of the built-in-file #[rune(span)] pub span: Span, /// The line number - pub value: ast::LitNumber, + pub value: Lit<'hir>, } /// An assign expression `a = b`. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq)] #[non_exhaustive] pub struct ExprAssign<'hir> { /// The expression being assigned to. @@ -208,7 +221,7 @@ pub struct ExprAssign<'hir> { } /// A `loop` expression: `loop { ... }`. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq)] #[non_exhaustive] pub struct ExprLoop<'hir> { /// A label. @@ -220,7 +233,7 @@ pub struct ExprLoop<'hir> { } /// A `for` loop over an iterator: `for i in [1, 2, 3] {}`. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq)] #[non_exhaustive] pub struct ExprFor<'hir> { /// The label of the loop. @@ -235,7 +248,7 @@ pub struct ExprFor<'hir> { } /// A let expression `let = ` -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, Clone, Copy, PartialEq, Spanned)] #[non_exhaustive] pub struct ExprLet<'hir> { /// The name of the binding. @@ -245,7 +258,7 @@ pub struct ExprLet<'hir> { } /// An if statement: `if cond { true } else { false }`. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq)] #[non_exhaustive] pub struct ExprIf<'hir> { /// The condition to the if statement. @@ -259,7 +272,7 @@ pub struct ExprIf<'hir> { } /// An else branch of an if expression. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, Clone, Copy, PartialEq, Spanned)] #[non_exhaustive] pub struct ExprElseIf<'hir> { /// Span of the expression. @@ -272,7 +285,7 @@ pub struct ExprElseIf<'hir> { } /// An else branch of an if expression. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, Clone, Copy, PartialEq, Spanned)] #[non_exhaustive] pub struct ExprElse<'hir> { /// Span of the expression. @@ -283,7 +296,7 @@ pub struct ExprElse<'hir> { } /// A match expression. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq)] #[non_exhaustive] pub struct ExprMatch<'hir> { /// The expression who's result we match over. @@ -293,7 +306,7 @@ pub struct ExprMatch<'hir> { } /// A match branch. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, Clone, Copy, PartialEq, Spanned)] #[non_exhaustive] pub struct ExprMatchBranch<'hir> { /// Span of the expression. @@ -308,7 +321,7 @@ pub struct ExprMatchBranch<'hir> { } /// A function call `()`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Opaque)] +#[derive(Debug, Clone, Copy, PartialEq, Opaque)] #[non_exhaustive] pub struct ExprCall<'hir> { /// Opaque identifier related with call. @@ -332,7 +345,7 @@ impl<'hir> ExprCall<'hir> { } /// A field access `.`. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq)] #[non_exhaustive] pub struct ExprFieldAccess<'hir> { /// The expr where the field is being accessed. @@ -342,7 +355,7 @@ pub struct ExprFieldAccess<'hir> { } /// The field being accessed. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq)] #[non_exhaustive] pub enum ExprField<'hir> { /// An identifier. @@ -352,7 +365,7 @@ pub enum ExprField<'hir> { } /// A binary expression. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq)] #[non_exhaustive] pub struct ExprBinary<'hir> { /// The left-hand side of a binary operation. @@ -364,7 +377,7 @@ pub struct ExprBinary<'hir> { } /// A unary expression. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq)] #[non_exhaustive] pub struct ExprUnary<'hir> { /// The operation to apply. @@ -374,7 +387,7 @@ pub struct ExprUnary<'hir> { } /// An index get operation `[]`. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq)] #[non_exhaustive] pub struct ExprIndex<'hir> { /// The target of the index set. @@ -384,7 +397,7 @@ pub struct ExprIndex<'hir> { } /// Things that we can break on. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq)] #[non_exhaustive] pub enum ExprBreakValue<'hir> { /// Breaking a value out of a loop. @@ -394,7 +407,7 @@ pub enum ExprBreakValue<'hir> { } /// A block expression. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq)] #[non_exhaustive] pub struct ExprBlock<'hir> { /// The kind of the block. @@ -406,7 +419,7 @@ pub struct ExprBlock<'hir> { } /// The kind of an [ExprBlock]. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq)] #[non_exhaustive] pub enum ExprBlockKind { Default, @@ -415,7 +428,7 @@ pub enum ExprBlockKind { } /// A `select` expression that selects over a collection of futures. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq)] #[non_exhaustive] pub struct ExprSelect<'hir> { /// The branches of the select. @@ -423,7 +436,7 @@ pub struct ExprSelect<'hir> { } /// A single selection branch. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, Clone, Copy, PartialEq, Spanned)] #[non_exhaustive] pub enum ExprSelectBranch<'hir> { /// A patterned branch. @@ -433,7 +446,7 @@ pub enum ExprSelectBranch<'hir> { } /// A single selection branch. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, Clone, Copy, PartialEq, Spanned)] #[non_exhaustive] pub struct ExprSelectPatBranch<'hir> { /// The identifier to bind the result to. @@ -445,7 +458,7 @@ pub struct ExprSelectPatBranch<'hir> { } /// A closure expression. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Opaque)] +#[derive(Debug, Clone, Copy, PartialEq, Opaque)] #[non_exhaustive] pub struct ExprClosure<'hir> { /// Opaque identifier for the closure. @@ -458,7 +471,7 @@ pub struct ExprClosure<'hir> { } /// An object expression. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq)] #[non_exhaustive] pub struct ExprObject<'hir> { /// An object identifier. @@ -468,7 +481,7 @@ pub struct ExprObject<'hir> { } /// A single field assignment in an object expression. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, Clone, Copy, PartialEq, Spanned)] #[non_exhaustive] pub struct FieldAssign<'hir> { /// Span of the field assignment. @@ -481,7 +494,7 @@ pub struct FieldAssign<'hir> { } /// Possible literal object keys. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, Clone, Copy, PartialEq, Spanned)] #[non_exhaustive] pub enum ObjectKey<'hir> { /// A literal string (with escapes). @@ -511,7 +524,7 @@ impl<'a, 'hir> Resolve<'a> for ObjectKey<'hir> { } /// A literal vector. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq)] #[non_exhaustive] pub struct ExprSeq<'hir> { /// Items in the vector. @@ -519,7 +532,7 @@ pub struct ExprSeq<'hir> { } /// A range expression `a .. b` or `a ..= b`. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq)] #[non_exhaustive] pub struct ExprRange<'hir> { /// Start of range. @@ -531,7 +544,7 @@ pub struct ExprRange<'hir> { } /// The limits of the specified range. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq)] #[non_exhaustive] pub enum ExprRangeLimits { /// Half-open range expression. @@ -541,7 +554,7 @@ pub enum ExprRangeLimits { } /// The condition in an if statement. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, Clone, Copy, PartialEq, Spanned)] #[non_exhaustive] pub enum Condition<'hir> { /// A regular expression. @@ -551,7 +564,7 @@ pub enum Condition<'hir> { } /// A path. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Opaque, Spanned)] +#[derive(Debug, Clone, Copy, PartialEq, Opaque, Spanned)] #[non_exhaustive] pub struct Path<'hir> { /// Opaque id associated with path. @@ -628,7 +641,7 @@ impl IntoExpectation for &Path<'_> { } /// A single path segment. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, Clone, Copy, PartialEq, Spanned)] #[non_exhaustive] pub struct PathSegment<'hir> { /// The span of the path segment. @@ -653,7 +666,7 @@ impl<'hir> PathSegment<'hir> { } /// A single segment in a path. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq)] #[non_exhaustive] pub enum PathSegmentKind<'hir> { /// A path segment that contains `Self`. @@ -670,7 +683,7 @@ pub enum PathSegmentKind<'hir> { Generics(&'hir [Expr<'hir>]), } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Opaque, Spanned)] +#[derive(Debug, Clone, Copy, PartialEq, Opaque, Spanned)] #[non_exhaustive] pub struct ItemFn<'hir> { /// Opaque identifier for fn item. @@ -690,7 +703,7 @@ pub struct ItemFn<'hir> { } /// A single argument to a function. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, Clone, Copy, PartialEq, Spanned)] #[non_exhaustive] pub enum FnArg<'hir> { /// The `self` parameter. @@ -700,7 +713,7 @@ pub enum FnArg<'hir> { } /// A block of statements. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Opaque, Spanned)] +#[derive(Debug, Clone, Copy, PartialEq, Opaque, Spanned)] #[non_exhaustive] pub struct Block<'hir> { /// The unique identifier for the block expression. @@ -723,7 +736,7 @@ impl Block<'_> { } /// A statement within a block. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, Clone, Copy, PartialEq, Spanned)] #[non_exhaustive] pub enum Stmt<'hir> { /// A local declaration. @@ -737,7 +750,7 @@ pub enum Stmt<'hir> { } /// A local variable declaration `let = ;` -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, Clone, Copy, PartialEq, Spanned)] #[non_exhaustive] pub struct Local<'hir> { /// The span of the local declaration. diff --git a/crates/rune/src/hir/lowering.rs b/crates/rune/src/hir/lowering.rs index 4bb7e3365..e1869788c 100644 --- a/crates/rune/src/hir/lowering.rs +++ b/crates/rune/src/hir/lowering.rs @@ -1,6 +1,12 @@ +use core::cell::Cell; +use core::ops::Neg; + +use num::ToPrimitive; + use crate::ast::{self, Spanned}; -use crate::compile::{self, HirErrorKind}; +use crate::compile::{self, CompileErrorKind, HirErrorKind, ParseErrorKind, WithSpan}; use crate::hir; +use crate::parse::Resolve; use crate::query::{self, Query}; /// Allocate a single object in the arena. @@ -17,6 +23,28 @@ macro_rules! alloc { }; } +/// Allocate a string into the arena. +macro_rules! alloc_str { + ($ctx:expr, $value:expr) => { + $ctx.arena + .alloc_str($value) + .map_err(|e| HirErrorKind::ArenaAllocError { + requested: e.requested, + }) + }; +} + +/// Allocate a byte string into the arena. +macro_rules! alloc_bytes { + ($ctx:expr, $value:expr) => { + $ctx.arena + .alloc_bytes($value) + .map_err(|e| HirErrorKind::ArenaAllocError { + requested: e.requested, + }) + }; +} + /// Unpacks an optional value and allocates it in the arena. macro_rules! option { ($ctx:expr, $span:expr; $value:expr, |$pat:pat_param| $closure:expr) => { @@ -65,12 +93,17 @@ pub struct Ctx<'hir, 'a> { /// Arena used for allocations. arena: &'hir hir::arena::Arena, q: Query<'a>, + in_template: Cell, } impl<'hir, 'a> Ctx<'hir, 'a> { - /// Construct a new contctx. + /// Construct a new context. pub(crate) fn new(arena: &'hir hir::arena::Arena, query: Query<'a>) -> Self { - Self { arena, q: query } + Self { + arena, + q: query, + in_template: Cell::new(false), + } } } @@ -191,10 +224,7 @@ pub(crate) fn expr<'hir>(ctx: &Ctx<'hir, '_>, ast: &ast::Expr) -> compile::Resul op: ast.op, rhs: alloc!(ctx, ast; expr(ctx, &ast.rhs)?), })), - ast::Expr::Unary(ast) => hir::ExprKind::Unary(alloc!(ctx, ast; hir::ExprUnary { - op: ast.op, - expr: alloc!(ctx, ast; expr(ctx, &ast.expr)?), - })), + ast::Expr::Unary(ast) => expr_unary(ctx, ast)?, ast::Expr::Index(ast) => hir::ExprKind::Index(alloc!(ctx, ast; hir::ExprIndex { target: alloc!(ctx, ast; expr(ctx, &ast.target)?), index: alloc!(ctx, ast; expr(ctx, &ast.index)?), @@ -232,7 +262,7 @@ pub(crate) fn expr<'hir>(ctx: &Ctx<'hir, '_>, ast: &ast::Expr) -> compile::Resul ast::Expr::Closure(ast) => { hir::ExprKind::Closure(alloc!(ctx, ast; expr_closure(ctx, ast)?)) } - ast::Expr::Lit(ast) => hir::ExprKind::Lit(alloc!(ctx, &ast.lit; ast.lit)), + ast::Expr::Lit(ast) => hir::ExprKind::Lit(lit(ast, ctx, &ast.lit)?), ast::Expr::Object(ast) => hir::ExprKind::Object(alloc!(ctx, ast; hir::ExprObject { path: object_ident(ctx, &ast.ident)?, assignments: iter!(ctx, ast; &ast.assignments, |(ast, _)| hir::FieldAssign { @@ -258,11 +288,18 @@ pub(crate) fn expr<'hir>(ctx: &Ctx<'hir, '_>, ast: &ast::Expr) -> compile::Resul ast::Expr::Group(ast) => hir::ExprKind::Group(alloc!(ctx, ast; expr(ctx, &ast.expr)?)), ast::Expr::MacroCall(ast) => { hir::ExprKind::MacroCall(alloc!(ctx, ast; match ctx.q.builtin_macro_for(ast)? { - query::BuiltInMacro::Template(ast) => hir::MacroCall::Template(alloc!(ctx, ast; hir::BuiltInTemplate { - span: ast.span, - from_literal: ast.from_literal, - exprs: iter!(ctx, ast; &ast.exprs, |ast| expr(ctx, ast)?), - })), + query::BuiltInMacro::Template(ast) => { + let old = ctx.in_template.replace(true); + + let result = hir::MacroCall::Template(alloc!(ctx, ast; hir::BuiltInTemplate { + span: ast.span, + from_literal: ast.from_literal, + exprs: iter!(ctx, ast; &ast.exprs, |ast| expr(ctx, ast)?), + })); + + ctx.in_template.set(old); + result + }, query::BuiltInMacro::Format(ast) => hir::MacroCall::Format(alloc!(ctx, ast; hir::BuiltInFormat { span: ast.span, fill: ast.fill, @@ -275,11 +312,11 @@ pub(crate) fn expr<'hir>(ctx: &Ctx<'hir, '_>, ast: &ast::Expr) -> compile::Resul })), query::BuiltInMacro::File(ast) => hir::MacroCall::File(alloc!(ctx, ast; hir::BuiltInFile { span: ast.span, - value: ast.value, + value: lit(ast, ctx, &ast.value)?, })), query::BuiltInMacro::Line(ast) => hir::MacroCall::Line(alloc!(ctx, ast; hir::BuiltInLine { span: ast.span, - value: ast.value, + value: lit(ast, ctx, &ast.value)?, })), } )) @@ -292,6 +329,91 @@ pub(crate) fn expr<'hir>(ctx: &Ctx<'hir, '_>, ast: &ast::Expr) -> compile::Resul }) } +pub(crate) fn lit<'hir>( + span: &dyn Spanned, + ctx: &Ctx<'hir, '_>, + ast: &ast::Lit, +) -> compile::Result> { + match ast { + ast::Lit::Bool(lit) => Ok(hir::Lit::Bool(lit.value)), + ast::Lit::Number(lit) => match lit.resolve(resolve_context!(ctx.q))? { + ast::Number::Float(n) => Ok(hir::Lit::Float(n)), + ast::Number::Integer(int) => { + let n = match int.to_i64() { + Some(n) => n, + None => { + return Err(compile::Error::new( + ast, + ParseErrorKind::BadNumberOutOfBounds, + )); + } + }; + + Ok(hir::Lit::Integer(n)) + } + }, + ast::Lit::Byte(lit) => { + let b = lit.resolve(resolve_context!(ctx.q))?; + Ok(hir::Lit::Byte(b)) + } + ast::Lit::Char(lit) => { + let ch = lit.resolve(resolve_context!(ctx.q))?; + Ok(hir::Lit::Char(ch)) + } + ast::Lit::Str(lit) => { + let string = if ctx.in_template.get() { + lit.resolve_template_string(resolve_context!(ctx.q))? + } else { + lit.resolve_string(resolve_context!(ctx.q))? + }; + + Ok(hir::Lit::Str( + alloc_str!(ctx, string.as_ref()).with_span(span)?, + )) + } + ast::Lit::ByteStr(lit) => { + let bytes = lit.resolve(resolve_context!(ctx.q))?; + Ok(hir::Lit::ByteStr( + alloc_bytes!(ctx, bytes.as_ref()).with_span(span)?, + )) + } + } +} + +pub(crate) fn expr_unary<'hir>( + ctx: &Ctx<'hir, '_>, + ast: &ast::ExprUnary, +) -> compile::Result> { + // NB: special unary expressions. + if let ast::UnOp::BorrowRef { .. } = ast.op { + return Err(compile::Error::new(ast, CompileErrorKind::UnsupportedRef)); + } + + let (ast::UnOp::Neg(..), ast::Expr::Lit(ast::ExprLit { lit: ast::Lit::Number(n), .. })) = (ast.op, &*ast.expr) else { + return Ok(hir::ExprKind::Unary(alloc!(ctx, ast; hir::ExprUnary { + op: ast.op, + expr: alloc!(ctx, ast; expr(ctx, &ast.expr)?), + }))); + }; + + match n.resolve(resolve_context!(ctx.q))? { + ast::Number::Float(n) => Ok(hir::ExprKind::Lit(hir::Lit::Float(-n))), + ast::Number::Integer(int) => { + let n = match int.neg().to_i64() { + Some(n) => n, + None => { + return Err(compile::Error::new( + ast, + ParseErrorKind::BadNumberOutOfBounds, + )); + } + }; + + Ok(hir::ExprKind::Lit(hir::Lit::Integer(n))) + } + } +} + /// Lower a block expression. pub(crate) fn expr_block<'hir>( ctx: &Ctx<'hir, '_>, diff --git a/crates/rune/src/indexing/index.rs b/crates/rune/src/indexing/index.rs index 6a575aa35..6a8b98414 100644 --- a/crates/rune/src/indexing/index.rs +++ b/crates/rune/src/indexing/index.rs @@ -367,13 +367,14 @@ impl<'a> Indexer<'a> { })?; let id = self.q.storage.insert_str(name); let source = ast::StrSource::Synthetic(id); - let node = ast::LitStr { + let value = ast::Lit::Str(ast::LitStr { span: ast.span(), source, - }; + }); + Ok(BuiltInMacro::File(BuiltInFile { span: ast.span(), - value: node, + value, })) } @@ -391,10 +392,10 @@ impl<'a> Indexer<'a> { Ok(BuiltInMacro::Line(BuiltInLine { span: ast.span(), - value: ast::LitNumber { + value: ast::Lit::Number(ast::LitNumber { span: ast.span(), source, - }, + }), })) } diff --git a/crates/rune/src/query.rs b/crates/rune/src/query.rs index 142bb2d09..82e3cdd52 100644 --- a/crates/rune/src/query.rs +++ b/crates/rune/src/query.rs @@ -131,7 +131,7 @@ pub(crate) struct BuiltInFile { #[rune(span)] pub(crate) span: Span, /// Path value to use - pub(crate) value: ast::LitStr, + pub(crate) value: ast::Lit, } /// Macro data for `line!()` @@ -141,7 +141,7 @@ pub(crate) struct BuiltInLine { #[rune(span)] pub(crate) span: Span, /// The line number - pub(crate) value: ast::LitNumber, + pub(crate) value: ast::Lit, } /// An entry in the build queue.