use std::fmt::{self, Display, Formatter};
use std::sync::Arc;
use std::sync::atomic::{AtomicU16, Ordering};
use super::enum_def::EnumDef;
use super::numeric::IntWidth;
use super::typeir::TypeIr;
pub type Reg = u16;
#[derive(Clone)]
pub enum Const {
Big(i128, IntWidth),
Float(f64),
F32(f32),
Char(char),
Str(Arc<str>),
Bytes(Arc<[u8]>),
}
pub const NO_CONV: u16 = u16::MAX;
pub const DISCARD: Reg = Reg::MAX;
pub const NO_ROOT: Reg = Reg::MAX;
#[derive(Clone, Copy, Debug)]
pub enum BinKind {
Add,
Sub,
Mul,
Div,
Rem,
Eq,
Ne,
Lt,
Le,
Gt,
Ge,
BitAnd,
BitOr,
BitXor,
Shl,
Shr,
}
pub fn overflow_message(op: BinKind) -> &'static str {
match op {
BinKind::Add => "attempt to add with overflow",
BinKind::Sub => "attempt to subtract with overflow",
BinKind::Mul => "attempt to multiply with overflow",
BinKind::Div => "attempt to divide with overflow",
BinKind::Rem => "attempt to calculate the remainder with overflow",
_ => "attempt to compute with overflow",
}
}
#[derive(Clone, Copy, Debug)]
pub enum UnKind {
Neg,
Not,
}
#[derive(Clone)]
pub enum Member {
Named(FieldName),
Indexed(usize),
}
pub struct FieldName {
pub name: Arc<str>,
slot: AtomicU16,
}
impl FieldName {
pub fn new(name: Arc<str>) -> FieldName {
FieldName {
name,
slot: AtomicU16::new(u16::MAX),
}
}
pub fn slot_in(&self, shape: &StructShape) -> Option<usize> {
let hint = self.slot.load(Ordering::Relaxed);
if let Some(field) = shape.fields.get(usize::from(hint))
&& (Arc::ptr_eq(field, &self.name) || **field == *self.name)
{
return Some(usize::from(hint));
}
let found = shape.slot(&self.name)?;
if let Ok(small) = u16::try_from(found) {
self.slot.store(small, Ordering::Relaxed);
}
Some(found)
}
}
impl Clone for FieldName {
fn clone(&self) -> FieldName {
FieldName {
name: self.name.clone(),
slot: AtomicU16::new(self.slot.load(Ordering::Relaxed)),
}
}
}
impl Display for FieldName {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str(&self.name)
}
}
#[derive(Clone, Copy)]
pub enum CapSource {
Local(Reg),
Upvalue(u16),
MutableLocal(Reg),
MutableUpvalue(u16),
}
impl CapSource {
pub fn is_mutable(self) -> bool {
matches!(self, Self::MutableLocal(_) | Self::MutableUpvalue(_))
}
}
pub struct StructLit {
pub filled: Arc<[bool]>,
pub shape: Arc<StructShape>,
pub has_rest: bool,
}
#[derive(Clone)]
pub struct EnumVariant {
pub def: Arc<EnumDef>,
pub variant: u16,
}
#[derive(Clone)]
pub enum DefaultIr {
Int(IntWidth),
F32,
F64,
Bool,
Char,
Str,
Unit,
Vec,
Map,
Set,
Opt,
Tuple(Vec<DefaultIr>),
Struct {
shape: Arc<StructShape>,
fields: Vec<DefaultIr>,
},
Enum(EnumVariant),
}
pub const NO_TYPE: u16 = u16::MAX;
pub const NO_ATOM: u32 = u32::MAX;
#[derive(Clone)]
pub struct MethodName {
pub text: String,
pub id: BuiltinId,
pub atom: u32,
pub scalar: Option<ScalarTy>,
pub default: Option<Arc<DefaultIr>>,
pub place: bool,
}
impl MethodName {
pub fn builtin(id: BuiltinId) -> MethodName {
MethodName {
text: id.name().to_string(),
id,
atom: NO_ATOM,
scalar: None,
default: None,
place: false,
}
}
}
impl Display for MethodName {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str(&self.text)
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum ScalarTy {
Int(IntWidth),
F32,
F64,
Bool,
Char,
Str,
Opt(Box<ScalarTy>),
List(Box<ScalarTy>),
Map(Box<ScalarTy>),
Set(Box<ScalarTy>),
Other,
}
impl ScalarTy {
pub fn lower(ty: &syn::Type) -> Option<Self> {
let syn::Type::Path(path) = ty else {
return None;
};
Self::lower_segment(path.path.segments.last()?)
}
pub fn lower_segment(segment: &syn::PathSegment) -> Option<Self> {
if let syn::PathArguments::AngleBracketed(args) = &segment.arguments {
let inner = || Box::new(Self::first_arg(args).unwrap_or(Self::Other));
return match segment.ident.to_string().as_str() {
"Option" => Some(Self::Opt(inner())),
"Vec" | "VecDeque" => Some(Self::List(inner())),
"HashMap" | "BTreeMap" => Some(Self::Map(Box::new(
Self::nth_arg(args, 1).unwrap_or(Self::Other),
))),
"HashSet" | "BTreeSet" => Some(Self::Set(inner())),
_ => None,
};
}
Some(match segment.ident.to_string().as_str() {
"f32" => Self::F32,
"f64" => Self::F64,
"bool" => Self::Bool,
"char" => Self::Char,
"String" | "str" => Self::Str,
name => Self::Int(IntWidth::parse(name)?),
})
}
fn first_arg(args: &syn::AngleBracketedGenericArguments) -> Option<Self> {
Self::nth_arg(args, 0)
}
fn nth_arg(args: &syn::AngleBracketedGenericArguments, n: usize) -> Option<Self> {
args.args
.iter()
.filter_map(|arg| match arg {
syn::GenericArgument::Type(ty) => Some(ty),
_ => None,
})
.nth(n)
.and_then(Self::lower)
}
}
include!(concat!(env!("OUT_DIR"), "/builtin_id.rs"));
include!(concat!(env!("OUT_DIR"), "/path_id.rs"));
#[derive(Clone)]
pub struct PathRef {
pub id: PathId,
pub segs: Vec<String>,
pub coerce: Option<TypeIr>,
}
impl PathRef {
pub fn new(segs: Vec<String>, coerce: Option<TypeIr>) -> Self {
PathRef {
id: PathId::resolve(&segs),
segs,
coerce,
}
}
pub fn user(segs: Vec<String>, coerce: Option<TypeIr>) -> Self {
PathRef {
id: PathId::Other,
segs,
coerce,
}
}
pub fn display(&self) -> String {
self.segs.join("::")
}
}
impl BuiltinId {
pub fn is_borrow(self) -> bool {
matches!(
self,
BuiltinId::Borrow
| BuiltinId::BorrowMut
| BuiltinId::TryBorrow
| BuiltinId::TryBorrowMut
)
}
pub fn receivers(self) -> &'static [&'static str] {
use BuiltinId::{
AndThen, Chars, Clone, CloneFrom, Concat, Contains, ContainsKey, Copied, EndsWith,
Entry, Filter, First, Get, Insert, IsEmpty, Iter, IterMut, Join, Keys, Last, Len,
Lines, Map, MapOr, OkOrElse, Parse, Pop, Push, PushStr, Remove, Retain, Sort, SortBy,
SortByCachedKey, SortByKey, Split, SplitFirst, SplitWhitespace, StartsWith, Take,
ToString, Trim, Unwrap, UnwrapOr, UnwrapOrElse, Values, WriteAll, WriteFmt, WriteStr,
};
match self {
Clone | ToString | CloneFrom => &["*"],
Len | IsEmpty | Get => &["Str", "Vec", "Map"],
Insert | Remove => &["Vec", "Map"],
ContainsKey | Entry | Keys | Values => &["Map"],
Iter => &["Vec", "Map", "Option"],
IterMut | Pop | First | Last | SplitFirst | Sort | SortByKey | SortByCachedKey
| SortBy | Join | Concat | Retain => &["Vec"],
Push | Contains => &["Str", "Vec"],
PushStr | SplitWhitespace | Split | Chars | Lines | Trim | StartsWith | EndsWith
| Parse | WriteAll | WriteStr | WriteFmt => &["Str"],
Take | Unwrap | UnwrapOr | UnwrapOrElse | Copied | Map | Filter | AndThen | MapOr
| OkOrElse => &["Option"],
_ => &[],
}
}
pub fn is_higher_order(self) -> bool {
use BuiltinId::{
Chars, Clone, CloneFrom, Cloned, Concat, Contains, ContainsKey, Copied, Count,
EndsWith, Entry, Enumerate, First, FirstMut, Get, GetMut, Insert, IntoIter, IntoKeys,
IntoValues, IsEmpty, Iter, IterMut, Join, Keys, Last, LastMut, Len, Lines, Parse, Pop,
Product, Push, PushStr, Remove, Rev, Skip, Sort, SortUnstable, Split, SplitFirst,
SplitWhitespace, StartsWith, Sum, Take, ToString, Trim, Unwrap, UnwrapOr, Values,
};
!matches!(
self,
Len | IsEmpty
| Clone
| ToString
| Get
| GetMut
| Insert
| ContainsKey
| Remove
| Entry
| Keys
| IntoKeys
| Values
| IntoValues
| Iter
| IntoIter
| IterMut
| Push
| Pop
| First
| FirstMut
| Last
| LastMut
| SplitFirst
| Contains
| Sort
| SortUnstable
| Join
| Concat
| Sum
| Product
| Enumerate
| Rev
| Count
| Take
| Skip
| PushStr
| CloneFrom
| SplitWhitespace
| Split
| Chars
| Lines
| Trim
| StartsWith
| EndsWith
| Parse
| Unwrap
| UnwrapOr
| Copied
| Cloned
)
}
}
#[derive(Clone)]
pub struct FmtSpec {
pub template: String,
pub positional: Vec<Reg>,
pub named: Vec<(String, Reg)>,
}
pub struct PatInfo {
pub pat: PPat,
pub binds: Vec<(String, Reg)>,
pub consts: Vec<Reg>,
}
#[derive(Clone)]
pub struct PTag {
pub name: Option<Arc<str>>,
pub variant: Option<(Arc<EnumDef>, u16)>,
}
impl PTag {
pub fn matches(&self, def: &Arc<EnumDef>, variant: u16) -> bool {
match &self.variant {
Some((want, index)) => EnumDef::same(want, def) && *index == variant,
None => self.name.as_deref() == Some(&**def.variant_name(variant)),
}
}
pub fn is_named(&self, name: &str) -> bool {
self.name.as_deref() == Some(name)
}
}
#[derive(Clone)]
pub enum PLit {
Int(i128),
Float(f64),
Bool(bool),
Str(String),
Char(char),
}
#[derive(Clone)]
pub enum PPat {
Wild,
Rest,
Ident {
name: String,
sub: Option<Box<PPat>>,
},
Lit(PLit),
Const(u16),
Tuple(Vec<PPat>),
TupleStruct {
tag: PTag,
elems: Vec<PPat>,
},
Path {
tag: PTag,
},
Struct {
name: Option<String>,
fields: Vec<(String, PPat)>,
},
Or(Vec<PPat>),
Slice(Vec<PPat>),
Range {
lo: Option<PLit>,
hi: Option<PLit>,
inclusive: bool,
},
Unsupported,
}
#[derive(Clone, Copy)]
pub enum MacroKind {
Println,
Print,
Eprintln,
Eprint,
Panic,
Anyhow,
Bail,
}
mod chunk;
pub use chunk::{Chunk, Op, StructShape, path_call_chunk};