use std::fmt; use crate::Span; #[derive(Debug)] pub struct Script { pub imports: Vec, pub global_vars: Vec, pub functions: Vec, pub data: Vec, } #[derive(Debug)] pub enum TopLevelItem { Import(Import), GlobalVar(GlobalVar), Function(Function), Data(Data), } #[derive(Debug)] pub struct Import { pub span: Span, pub import: String, pub type_: ImportType, } #[derive(Debug)] pub enum ImportType { Memory(u32), Variable { name: String, type_: Type, mutable: bool, }, Function { name: String, params: Vec, result: Option, }, } #[derive(Debug)] pub struct GlobalVar { pub span: Span, pub name: String, pub value: Expression, pub type_: Option, pub mutable: bool, } #[derive(Debug)] pub struct Function { pub span: Span, pub export: bool, pub name: String, pub params: Vec<(String, Type)>, pub type_: Option, pub body: Expression, } #[derive(Debug)] pub struct Data { pub offset: Box, pub data: Vec, } #[derive(Debug)] pub enum DataValues { Array { type_: DataType, values: Vec, }, String(String), } #[derive(Debug, Clone)] pub enum DataType { I8, I16, I32, I64, F32, F64, } #[derive(Debug)] pub struct MemoryLocation { pub span: Span, pub size: MemSize, pub left: Box, pub right: Box, } #[derive(Debug)] pub struct Expression { pub type_: Option, pub expr: Expr, pub span: Span, } impl Expression { pub fn const_i32(&self) -> i32 { match self.expr { Expr::I32Const(v) => v, _ => panic!("Expected I32Const") } } pub fn const_i64(&self) -> i64 { match self.expr { Expr::I64Const(v) => v, _ => panic!("Expected I64Const") } } pub fn const_f32(&self) -> f32 { match self.expr { Expr::F32Const(v) => v, _ => panic!("Expected F32Const") } } pub fn const_f64(&self) -> f64 { match self.expr { Expr::F64Const(v) => v, _ => panic!("Expected F64Const") } } } #[derive(Debug)] pub enum Expr { Block { statements: Vec, final_expression: Option>, }, I32Const(i32), I64Const(i64), F32Const(f32), F64Const(f64), Variable(String), Let { name: String, type_: Option, value: Option>, let_type: LetType, }, Poke { mem_location: MemoryLocation, value: Box, }, Peek(MemoryLocation), Loop { label: String, block: Box, }, LabelBlock { label: String, block: Box, }, Branch(String), BranchIf { condition: Box, label: String, }, UnaryOp { op: UnaryOp, value: Box, }, BinOp { op: BinOp, left: Box, right: Box, }, Assign { name: String, value: Box, }, LocalTee { name: String, value: Box, }, Cast { value: Box, type_: Type, }, FuncCall { name: String, params: Vec, }, Select { condition: Box, if_true: Box, if_false: Box, }, If { condition: Box, if_true: Box, if_false: Option>, }, Return { value: Option>, }, First { value: Box, drop: Box, }, Error, } impl Expr { pub fn with_span(self, span: Span) -> Expression { Expression { type_: None, expr: self, span: span, } } } #[derive(Debug, Clone, Copy)] pub enum LetType { Normal, Lazy, Inline, } #[derive(Debug, Clone, Copy)] pub enum UnaryOp { Negate, Not, } #[derive(Debug, Clone, Copy)] pub enum BinOp { Add, Sub, Mul, Div, DivU, Rem, RemU, And, Or, Xor, Eq, Ne, Gt, GtU, Ge, GeU, Lt, LtU, Le, LeU, Shl, ShrU, ShrS, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum MemSize { Byte, Word, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] pub enum Type { I32, I64, F32, F64, } impl fmt::Display for Type { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Type::I32 => write!(f, "i32"), Type::I64 => write!(f, "i64"), Type::F32 => write!(f, "f32"), Type::F64 => write!(f, "f64"), } } }