From fa5c49c8ea790d0ea114ea0a4ab3c987ca8b7e0c Mon Sep 17 00:00:00 2001 From: Taehwan Kim Date: Mon, 28 Oct 2024 19:51:43 +0900 Subject: [PATCH 01/10] move syntax parser to LALR parser with rusty_lr --- Cargo.lock | 62 ++ Cargo.toml | 1 + src/ast/declarator.rs | 252 ++--- src/ast/expression.rs | 2428 +---------------------------------------- src/ast/mod.rs | 46 +- src/ast/parser.rs | 2214 ------------------------------------- src/ast/parser_lr.rs | 1237 +++++++++++++++++++++ src/ast/statement.rs | 789 +------------ src/ast/typename.rs | 349 ------ src/token/token.rs | 16 +- 10 files changed, 1517 insertions(+), 5877 deletions(-) delete mode 100644 src/ast/parser.rs create mode 100644 src/ast/parser_lr.rs delete mode 100644 src/ast/typename.rs diff --git a/Cargo.lock b/Cargo.lock index 7599401..04bc0e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,11 +6,73 @@ version = 3 name = "mini-c-parser" version = "0.12.2" dependencies = [ + "rusty_lr", "rusty_parser", ] +[[package]] +name = "proc-macro2" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rusty_lr" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95fa482f4c998edbbfeff2fcb96b69567809fbc8fd1622a2de37bd028a4e250f" +dependencies = [ + "rusty_lr_core", + "rusty_lr_derive", +] + +[[package]] +name = "rusty_lr_core" +version = "3.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd65ae873d5a464a7e13da4726ce9c2673b2883bbef3c33e1e8457b453e531c" + +[[package]] +name = "rusty_lr_derive" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcfbb05383747127509a3d5b22b799f41f5becc61afe35cba3718da1a052e77c" +dependencies = [ + "proc-macro2", + "rusty_lr_parser", +] + +[[package]] +name = "rusty_lr_parser" +version = "3.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "825ccff885cbc05b28054300a9eaa816e575ab5bf04b8637b7c18f1821061d32" +dependencies = [ + "proc-macro2", + "quote", + "rusty_lr_core", +] + [[package]] name = "rusty_parser" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0d4bd88bbc485acc1f3d26157ad5dd519e08c0e5a265a9601a8245b4eb195cd" + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" diff --git a/Cargo.toml b/Cargo.toml index dd9c803..494e5d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,3 +11,4 @@ categories = ["parser-implementations", "compilers"] [dependencies] rusty_parser = "1.1.0" +rusty_lr = "3.3.1" diff --git a/src/ast/declarator.rs b/src/ast/declarator.rs index 0a300f7..bc19351 100644 --- a/src/ast/declarator.rs +++ b/src/ast/declarator.rs @@ -1,211 +1,139 @@ use super::expression::Expression; -use super::typename::TypeInfo; use std::vec::Vec; #[derive(Debug, Clone)] -pub enum Declarator { - Identifier(DeclIdentifier), - DirectArrayFixed(DeclDirectArrayFixed), - DirectArrayUnbounded(DeclDirectArrayUnbounded), - DirectFunction(DeclDirectFunction), - Const(DeclConst), - Pointer(DeclPointer), - Init(DeclInit), - AbstractArrayFixed(DeclAbstractArrayFixed), - AbstractArrayUnbounded(DeclAbstractArrayUnbounded), - AbstractFunction(DeclAbstractFunction), - AbstractPointer(DeclAbstractPointer), - AbstractConst(DeclAbstractConst), -} - -impl Declarator { - pub fn resolve_typeinfo(&self, info: TypeInfo) -> (Option, TypeInfo) { - match self { - Declarator::Identifier(decl) => decl.resolve_typeinfo(info), - Declarator::DirectArrayFixed(decl) => decl.resolve_typeinfo(info), - Declarator::DirectArrayUnbounded(decl) => decl.resolve_typeinfo(info), - Declarator::DirectFunction(decl) => decl.resolve_typeinfo(info), - Declarator::Const(decl) => decl.resolve_typeinfo(info), - Declarator::Pointer(decl) => decl.resolve_typeinfo(info), - Declarator::Init(decl) => decl.resolve_typeinfo(info), - Declarator::AbstractArrayFixed(decl) => decl.resolve_typeinfo(info), - Declarator::AbstractArrayUnbounded(decl) => decl.resolve_typeinfo(info), - Declarator::AbstractFunction(decl) => decl.resolve_typeinfo(info), - Declarator::AbstractPointer(decl) => decl.resolve_typeinfo(info), - Declarator::AbstractConst(decl) => decl.resolve_typeinfo(info), - } - } +pub enum StorageClassSpecifier { + Static, + Typedef, + Extern, + Auto, + Register, } - #[derive(Debug, Clone)] -pub struct DeclIdentifier { - pub name: String, +pub enum TypeQualifier { + Const, + Volatile, } -impl DeclIdentifier { - pub fn resolve_typeinfo(&self, info: TypeInfo) -> (Option, TypeInfo) { - (Some(self.name.clone()), info) - } +#[derive(Debug, Clone)] +pub enum TypeSpecifier { + Void, + Char, + Short, + Int, + Long, + Float, + Double, + Signed, + Unsigned, + Typename(String), + StructOrUnion(StructOrUnionSpecifier), + Enum(EnumSpecifier), } #[derive(Debug, Clone)] -pub struct DeclDirectArrayFixed { - pub declarator: Box, - pub size: Expression, -} -impl DeclDirectArrayFixed { - pub fn resolve_typeinfo(&self, info: TypeInfo) -> (Option, TypeInfo) { - let (name, info) = self.declarator.resolve_typeinfo(info); - let size = self - .size - .get_constant_i64() - .expect("Array size must be constant") as usize; - (name, TypeInfo::Array(Box::new(info), Some(size))) - } +pub struct StructOrUnionSpecifier { + pub is_struct: bool, + pub name: Option, + pub decls: Option>, } #[derive(Debug, Clone)] -pub struct DeclDirectArrayUnbounded { - pub declarator: Box, +pub struct StructDeclaration { + pub specs: Vec, + pub declarators: Vec, } -impl DeclDirectArrayUnbounded { - pub fn resolve_typeinfo(&self, info: TypeInfo) -> (Option, TypeInfo) { - let (name, info) = self.declarator.resolve_typeinfo(info); - (name, TypeInfo::Array(Box::new(info), None)) - } + +#[derive(Debug, Clone)] +pub struct EnumSpecifier { + pub name: Option, + pub enumerators: Option>, } #[derive(Debug, Clone)] -pub struct DeclDirectFunction { - pub declarator: Box, - pub params: Vec<(Option, TypeInfo)>, +pub struct Enumerator { + pub name: String, + pub value: Option, } -impl DeclDirectFunction { - pub fn resolve_typeinfo(&self, info: TypeInfo) -> (Option, TypeInfo) { - let (name, return_type) = self.declarator.resolve_typeinfo(info); - let mut params = Vec::new(); - for (_, param_type) in &self.params { - params.push(param_type.clone()); - } - (name, TypeInfo::Function(Box::new(return_type), params)) - } + +#[derive(Debug, Clone)] +pub enum DeclarationSpecifier { + StorageClassSpecifier(StorageClassSpecifier), + TypeQualifier(TypeQualifier), + TypeSpecifier(TypeSpecifier), } + #[derive(Debug, Clone)] -pub struct DeclConst { - pub declarator: Box, +pub enum SpecifierQualifier { + TypeQualifier(TypeQualifier), + TypeSpecifier(TypeSpecifier), } -impl DeclConst { - pub fn resolve_typeinfo(&self, info: TypeInfo) -> (Option, TypeInfo) { - let (name, info) = self.declarator.resolve_typeinfo(info); - (name, TypeInfo::Const(Box::new(info))) - } + +#[derive(Debug, Clone)] +pub struct Typename { + pub specs: Vec, + pub declarator: Option>, } #[derive(Debug, Clone)] -pub struct DeclPointer { - pub declarator: Box, +pub struct ParameterDeclaration { + pub specs: Vec, + pub declarator: Option>, } -impl DeclPointer { - pub fn resolve_typeinfo(&self, info: TypeInfo) -> (Option, TypeInfo) { - let (name, info) = self.declarator.resolve_typeinfo(info); - (name, TypeInfo::Pointer(Box::new(info))) - } +#[derive(Debug, Clone)] +pub struct ParameterList { + pub params: Vec, + pub variadic: bool, } #[derive(Debug, Clone)] -pub struct DeclInit { - pub declarator: Box, - pub initializer: Option, +pub enum Declarator { + Identifier(DeclIdentifier), + Const(DeclConst), + Pointer(DeclPointer), + Volatile(DeclVolatile), + ArrayFixed(DeclArrayFixed), + ArrayUnbounded(DeclArrayUnbounded), + Function(DeclFunction), } -impl DeclInit { - pub fn resolve_typeinfo(&self, info: TypeInfo) -> (Option, TypeInfo) { - self.declarator.resolve_typeinfo(info) - } + +#[derive(Debug, Clone)] +pub struct DeclIdentifier { + pub name: String, } #[derive(Debug, Clone)] -pub struct DeclAbstractArrayFixed { +pub struct DeclConst { pub declarator: Option>, - pub size: Expression, -} -impl DeclAbstractArrayFixed { - pub fn resolve_typeinfo(&self, info: TypeInfo) -> (Option, TypeInfo) { - let (name, info_) = if let Some(decl) = &self.declarator { - decl.resolve_typeinfo(info) - } else { - (None, info) - }; - let size = self - .size - .get_constant_i64() - .expect("Array size must be constant") as usize; - (name, TypeInfo::Array(Box::new(info_), Some(size))) - } } #[derive(Debug, Clone)] -pub struct DeclAbstractArrayUnbounded { +pub struct DeclPointer { + pub declarator: Option>, +} +#[derive(Debug, Clone)] +pub struct DeclVolatile { pub declarator: Option>, } -impl DeclAbstractArrayUnbounded { - pub fn resolve_typeinfo(&self, info: TypeInfo) -> (Option, TypeInfo) { - let (name, info_) = if let Some(decl) = &self.declarator { - decl.resolve_typeinfo(info) - } else { - (None, info) - }; - (name, TypeInfo::Array(Box::new(info_), None)) - } +#[derive(Debug, Clone)] +pub struct DeclInit { + pub declarator: Box, + pub initializer: Option, } #[derive(Debug, Clone)] -pub struct DeclAbstractFunction { - pub declarator: Option>, - pub params: Vec<(Option, TypeInfo)>, -} -impl DeclAbstractFunction { - pub fn resolve_typeinfo(&self, info: TypeInfo) -> (Option, TypeInfo) { - let (name, return_type) = if let Some(decl) = &self.declarator { - decl.resolve_typeinfo(info) - } else { - (None, info) - }; - ( - name, - TypeInfo::Function( - Box::new(return_type), - self.params.iter().map(|(_, t)| t.clone()).collect(), - ), - ) - } -} - -#[derive(Debug, Clone)] -pub struct DeclAbstractPointer { +pub struct DeclArrayFixed { pub declarator: Option>, -} -impl DeclAbstractPointer { - pub fn resolve_typeinfo(&self, info: TypeInfo) -> (Option, TypeInfo) { - let (name, info_) = if let Some(decl) = &self.declarator { - decl.resolve_typeinfo(info) - } else { - (None, info) - }; - (name, TypeInfo::Pointer(Box::new(info_))) - } + pub size: Expression, } #[derive(Debug, Clone)] -pub struct DeclAbstractConst { +pub struct DeclArrayUnbounded { pub declarator: Option>, } -impl DeclAbstractConst { - pub fn resolve_typeinfo(&self, info: TypeInfo) -> (Option, TypeInfo) { - let (name, info_) = if let Some(decl) = &self.declarator { - decl.resolve_typeinfo(info) - } else { - (None, info) - }; - (name, TypeInfo::Const(Box::new(info_))) - } + +#[derive(Debug, Clone)] +pub struct DeclFunction { + pub declarator: Option>, + pub params: ParameterList, } diff --git a/src/ast/expression.rs b/src/ast/expression.rs index a6a694a..bc07492 100644 --- a/src/ast/expression.rs +++ b/src/ast/expression.rs @@ -1,1147 +1,150 @@ -use super::typename::TypeInfo; -use crate::virtualmachine::instruction::generation::InstructionGenerator; -use crate::virtualmachine::instruction::generation::VariableOffset; -use crate::virtualmachine::instruction::operand::Operand; -use crate::virtualmachine::instruction::*; -use crate::virtualmachine::program::STACK_POINTER_BASE_REGISTER; -use crate::virtualmachine::program::STACK_POINTER_REGISTER; -use crate::virtualmachine::program::TEXT_SIZE_REGISTER; -use crate::virtualmachine::variable::VariableData; +use super::declarator; #[derive(Debug, Clone)] pub enum Expression { - Void(ExprVoid), - PrimaryIdentifier(ExprPrimaryIdentifier), - PostMember(ExprPostMember), + Identifier(ExprIdentifier), + + ConstantCharacter(ExprConstantCharacter), ConstantInteger(ExprConstantInteger), ConstantUnsignedInteger(ExprConstantUnsignedInteger), - ConstantCharacter(ExprConstantCharacter), ConstantLong(ExprConstantLong), ConstantUnsignedLong(ExprConstantUnsignedLong), ConstantFloat(ExprConstantFloat), ConstantDouble(ExprConstantDouble), - StringLiteral(ExprString), - PostBracket(ExprPostBracket), - PostParen(ExprPostParen), - PostIncrement(ExprPostIncrement), - PostDecrement(ExprPostDecrement), + String(ExprString), + + Member(ExprMember), + Arrow(ExprArrow), + Bracket(ExprBracket), + Paren(ExprParen), Cast(ExprCast), SizeofType(ExprSizeOfType), SizeofExpr(ExprSizeOfExpr), - Unary(ExprUnary), - LogicalBinary(ExprLogicalBinary), - Comparison(ExprComparison), - Assign(ExprAssign), - AssignOp(ExprAssignOp), - - Additive(ExprAdditive), - Multiplicative(ExprMultiplicative), - Shift(ExprShift), - Bitwise(ExprBitwise), - PostArrow(ExprPostArrow), Conditional(ExprConditional), - Comma(ExprComma), - InitializerList(ExprInitializerList), -} -impl Expression { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - match self { - Expression::Void(expr) => expr.emit(instructions), - Expression::PrimaryIdentifier(expr) => expr.emit(instructions), - Expression::PostMember(expr) => expr.emit(instructions), - Expression::ConstantInteger(expr) => expr.emit(instructions), - Expression::ConstantUnsignedInteger(expr) => expr.emit(instructions), - Expression::ConstantCharacter(expr) => expr.emit(instructions), - Expression::ConstantLong(expr) => expr.emit(instructions), - Expression::ConstantUnsignedLong(expr) => expr.emit(instructions), - Expression::ConstantFloat(expr) => expr.emit(instructions), - Expression::ConstantDouble(expr) => expr.emit(instructions), - Expression::StringLiteral(expr) => expr.emit(instructions), - Expression::PostBracket(expr) => expr.emit(instructions), - Expression::PostParen(expr) => expr.emit(instructions), - Expression::PostIncrement(expr) => expr.emit(instructions), - Expression::PostDecrement(expr) => expr.emit(instructions), - Expression::Cast(expr) => expr.emit(instructions), - Expression::SizeofType(expr) => expr.emit(instructions), - Expression::SizeofExpr(expr) => expr.emit(instructions), - Expression::Unary(expr) => expr.emit(instructions), - Expression::LogicalBinary(expr) => expr.emit(instructions), - Expression::Comparison(expr) => expr.emit(instructions), - Expression::Assign(expr) => expr.emit(instructions), - Expression::AssignOp(expr) => expr.emit(instructions), - Expression::Additive(expr) => expr.emit(instructions), - Expression::Multiplicative(expr) => expr.emit(instructions), - Expression::Shift(expr) => expr.emit(instructions), - Expression::Bitwise(expr) => expr.emit(instructions), - Expression::PostArrow(expr) => expr.emit(instructions), - Expression::Conditional(expr) => expr.emit(instructions), - Expression::Comma(expr) => expr.emit(instructions), - Expression::InitializerList(expr) => expr.emit(instructions), - } - } - pub fn get_typeinfo(&self, instructions: &InstructionGenerator) -> TypeInfo { - match self { - Expression::Void(expr) => expr.get_typeinfo(instructions), - Expression::PrimaryIdentifier(expr) => expr.get_typeinfo(instructions), - Expression::PostMember(expr) => expr.get_typeinfo(instructions), - Expression::ConstantInteger(expr) => expr.get_typeinfo(instructions), - Expression::ConstantUnsignedInteger(expr) => expr.get_typeinfo(instructions), - Expression::ConstantCharacter(expr) => expr.get_typeinfo(instructions), - Expression::ConstantLong(expr) => expr.get_typeinfo(instructions), - Expression::ConstantUnsignedLong(expr) => expr.get_typeinfo(instructions), - Expression::ConstantFloat(expr) => expr.get_typeinfo(instructions), - Expression::ConstantDouble(expr) => expr.get_typeinfo(instructions), - Expression::StringLiteral(expr) => expr.get_typeinfo(instructions), - Expression::PostBracket(expr) => expr.get_typeinfo(instructions), - Expression::PostParen(expr) => expr.get_typeinfo(instructions), - Expression::PostIncrement(expr) => expr.get_typeinfo(instructions), - Expression::PostDecrement(expr) => expr.get_typeinfo(instructions), - Expression::Cast(expr) => expr.get_typeinfo(instructions), - Expression::SizeofType(expr) => expr.get_typeinfo(instructions), - Expression::SizeofExpr(expr) => expr.get_typeinfo(instructions), - Expression::Unary(expr) => expr.get_typeinfo(instructions), - Expression::LogicalBinary(expr) => expr.get_typeinfo(instructions), - Expression::Comparison(expr) => expr.get_typeinfo(instructions), - Expression::Assign(expr) => expr.get_typeinfo(instructions), - Expression::AssignOp(expr) => expr.get_typeinfo(instructions), - Expression::Additive(expr) => expr.get_typeinfo(instructions), - Expression::Multiplicative(expr) => expr.get_typeinfo(instructions), - Expression::Shift(expr) => expr.get_typeinfo(instructions), - Expression::Bitwise(expr) => expr.get_typeinfo(instructions), - Expression::PostArrow(expr) => expr.get_typeinfo(instructions), - Expression::Conditional(expr) => expr.get_typeinfo(instructions), - Expression::Comma(expr) => expr.get_typeinfo(instructions), - Expression::InitializerList(expr) => expr.get_typeinfo(instructions), - } - } - pub fn is_return_reference(&self, instructions: &InstructionGenerator) -> bool { - match self { - Expression::Void(expr) => expr.is_return_reference(instructions), - Expression::PrimaryIdentifier(expr) => expr.is_return_reference(instructions), - Expression::PostMember(expr) => expr.is_return_reference(instructions), - Expression::ConstantInteger(expr) => expr.is_return_reference(instructions), - Expression::ConstantUnsignedInteger(expr) => expr.is_return_reference(instructions), - Expression::ConstantCharacter(expr) => expr.is_return_reference(instructions), - Expression::ConstantLong(expr) => expr.is_return_reference(instructions), - Expression::ConstantUnsignedLong(expr) => expr.is_return_reference(instructions), - Expression::ConstantFloat(expr) => expr.is_return_reference(instructions), - Expression::ConstantDouble(expr) => expr.is_return_reference(instructions), - Expression::StringLiteral(expr) => expr.is_return_reference(instructions), - Expression::PostBracket(expr) => expr.is_return_reference(instructions), - Expression::PostParen(expr) => expr.is_return_reference(instructions), - Expression::PostIncrement(expr) => expr.is_return_reference(instructions), - Expression::PostDecrement(expr) => expr.is_return_reference(instructions), - Expression::Cast(expr) => expr.is_return_reference(instructions), - Expression::SizeofType(expr) => expr.is_return_reference(instructions), - Expression::SizeofExpr(expr) => expr.is_return_reference(instructions), - Expression::Unary(expr) => expr.is_return_reference(instructions), - Expression::LogicalBinary(expr) => expr.is_return_reference(instructions), - Expression::Comparison(expr) => expr.is_return_reference(instructions), - Expression::Assign(expr) => expr.is_return_reference(instructions), - Expression::AssignOp(expr) => expr.is_return_reference(instructions), - Expression::Additive(expr) => expr.is_return_reference(instructions), - Expression::Multiplicative(expr) => expr.is_return_reference(instructions), - Expression::Shift(expr) => expr.is_return_reference(instructions), - Expression::Bitwise(expr) => expr.is_return_reference(instructions), - Expression::PostArrow(expr) => expr.is_return_reference(instructions), - Expression::Conditional(expr) => expr.is_return_reference(instructions), - Expression::Comma(expr) => expr.is_return_reference(instructions), - Expression::InitializerList(expr) => expr.is_return_reference(instructions), - } - } - pub fn get_constant_i64(&self) -> Result { - match self { - Expression::ConstantInteger(expr) => expr.get_constant_i64(), - Expression::ConstantUnsignedInteger(expr) => expr.get_constant_i64(), - Expression::ConstantCharacter(expr) => expr.get_constant_i64(), - Expression::ConstantLong(expr) => expr.get_constant_i64(), - Expression::ConstantUnsignedLong(expr) => expr.get_constant_i64(), - Expression::SizeofType(expr) => expr.get_constant_i64(), - _ => Err("Not a constant expression".to_string()), - } - } -} + Unary(ExprUnary), + Binary(ExprBinary), -/// expression that always returns true int32(1) -#[derive(Debug, Clone)] -pub struct ExprVoid {} -impl ExprVoid { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Value(VariableData::Int32(1)), - operand_to: Operand::Register(0), - })); - } - pub fn get_typeinfo(&self, _instructions: &InstructionGenerator) -> TypeInfo { - TypeInfo::Int32 - } - pub fn is_return_reference(&self, _instructions: &InstructionGenerator) -> bool { - false - } + InitializerList(ExprInitializerList), } -/// for variable #[derive(Debug, Clone)] -pub struct ExprPrimaryIdentifier { +pub struct ExprIdentifier { pub name: String, } -// push pointer -impl ExprPrimaryIdentifier { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - let offset = instructions - .search_variable(&self.name) - .expect(format!("Variable {} not found", self.name).as_str()) - .1; - match offset { - VariableOffset::Global(absolute_offset) => { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Value(VariableData::UInt64(absolute_offset as u64)), - operand_to: Operand::Register(0), - })); - instructions.push(Instruction::AddAssign(AddAssign { - lhs: Operand::Register(0), - rhs: Operand::Register(TEXT_SIZE_REGISTER), - })); - } - VariableOffset::Local(relative_offset) => { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Register(STACK_POINTER_BASE_REGISTER), - operand_to: Operand::Register(0), - })); - instructions.push(Instruction::AddAssign(AddAssign { - lhs: Operand::Register(0), - rhs: Operand::Value(VariableData::Int64(relative_offset as i64)), - })); - } - } - } - pub fn is_return_reference(&self, instructions: &InstructionGenerator) -> bool { - match self.get_typeinfo(instructions).remove_const() { - TypeInfo::Array(_, _) => false, - _ => true, - } - } - pub fn get_typeinfo(&self, instructions: &InstructionGenerator) -> TypeInfo { - instructions - .search_variable(&self.name) - .expect(format!("Variable {} not found", self.name).as_str()) - .0 - } -} -/// for struct member access +/// 'c' character #[derive(Debug, Clone)] -pub struct ExprPostMember { - pub src: Box, - pub member: String, -} -impl ExprPostMember { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - let member_offset = match self.src.get_typeinfo(instructions).remove_const() { - TypeInfo::Struct(sinfo) => { - let mut member_offset: Option = None; - for (_, name, offset) in sinfo.fields.as_ref().unwrap() { - if name == &self.member { - member_offset = Some(*offset); - break; - } - } - member_offset.expect(format!("Field {} not found", self.member).as_str()) - } - _ => panic!("PostMember on non-struct type"), - }; - self.src.emit(instructions); - instructions.push(Instruction::AddAssign(AddAssign { - lhs: Operand::Register(0), - rhs: Operand::Value(VariableData::UInt64(member_offset as u64)), - })); - } - pub fn get_typeinfo(&self, instructions: &InstructionGenerator) -> TypeInfo { - let src_type = self.src.get_typeinfo(instructions); - match src_type.remove_const() { - TypeInfo::Struct(sinfo) => { - let mut member_type: Option = None; - for (t, name, _) in sinfo.fields.as_ref().unwrap() { - if name == &self.member { - member_type = Some(t.clone()); - break; - } - } - let member_type = - member_type.expect(format!("Field {} not found", self.member).as_str()); - if src_type.is_const() { - member_type.add_const() - } else { - member_type - } - } - _ => panic!("PostMember on non-struct type"), - } - } - pub fn is_return_reference(&self, instructions: &InstructionGenerator) -> bool { - match self.get_typeinfo(instructions).remove_const() { - TypeInfo::Array(_, _) => false, - _ => true, - } - } +pub struct ExprConstantCharacter { + pub value: i8, } - /// constant integer #[derive(Debug, Clone)] pub struct ExprConstantInteger { pub value: i32, } -impl ExprConstantInteger { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Value(VariableData::Int32(self.value)), - operand_to: Operand::Register(0), - })); - } - pub fn get_constant_i64(&self) -> Result { - Ok(self.value as i64) - } - pub fn get_typeinfo(&self, _instructions: &InstructionGenerator) -> TypeInfo { - TypeInfo::Int32 - } - pub fn is_return_reference(&self, _instructions: &InstructionGenerator) -> bool { - false - } -} - /// constant unsigned integer #[derive(Debug, Clone)] pub struct ExprConstantUnsignedInteger { pub value: u32, } -impl ExprConstantUnsignedInteger { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Value(VariableData::UInt32(self.value)), - operand_to: Operand::Register(0), - })); - } - pub fn get_constant_i64(&self) -> Result { - Ok(self.value as i64) - } - pub fn get_typeinfo(&self, _instructions: &InstructionGenerator) -> TypeInfo { - TypeInfo::UInt32 - } - pub fn is_return_reference(&self, _instructions: &InstructionGenerator) -> bool { - false - } -} - -/// 'c' character -#[derive(Debug, Clone)] -pub struct ExprConstantCharacter { - pub value: i8, -} -impl ExprConstantCharacter { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Value(VariableData::Int8(self.value)), - operand_to: Operand::Register(0), - })); - } - pub fn get_constant_i64(&self) -> Result { - Ok(self.value as i64) - } - pub fn get_typeinfo(&self, _instructions: &InstructionGenerator) -> TypeInfo { - TypeInfo::Int8 - } - pub fn is_return_reference(&self, _instructions: &InstructionGenerator) -> bool { - false - } -} - /// constant long #[derive(Debug, Clone)] pub struct ExprConstantLong { pub value: i64, } -impl ExprConstantLong { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Value(VariableData::Int64(self.value)), - operand_to: Operand::Register(0), - })); - } - pub fn get_constant_i64(&self) -> Result { - Ok(self.value as i64) - } - pub fn get_typeinfo(&self, _instructions: &InstructionGenerator) -> TypeInfo { - TypeInfo::Int64 - } - pub fn is_return_reference(&self, _instructions: &InstructionGenerator) -> bool { - false - } -} - /// constant unsigned long #[derive(Debug, Clone)] pub struct ExprConstantUnsignedLong { pub value: u64, } -impl ExprConstantUnsignedLong { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Value(VariableData::UInt64(self.value)), - operand_to: Operand::Register(0), - })); - } - pub fn get_constant_i64(&self) -> Result { - Ok(self.value as i64) - } - pub fn get_typeinfo(&self, _instructions: &InstructionGenerator) -> TypeInfo { - TypeInfo::UInt64 - } - pub fn is_return_reference(&self, _instructions: &InstructionGenerator) -> bool { - false - } -} /// constant float #[derive(Debug, Clone)] pub struct ExprConstantFloat { pub value: f32, } -impl ExprConstantFloat { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Value(VariableData::Float32(self.value)), - operand_to: Operand::Register(0), - })); - } - pub fn get_typeinfo(&self, _instructions: &InstructionGenerator) -> TypeInfo { - TypeInfo::Float32 - } - pub fn is_return_reference(&self, _instructions: &InstructionGenerator) -> bool { - false - } -} /// constant double #[derive(Debug, Clone)] pub struct ExprConstantDouble { pub value: f64, } -impl ExprConstantDouble { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Value(VariableData::Float64(self.value)), - operand_to: Operand::Register(0), - })); - } - pub fn get_typeinfo(&self, _instructions: &InstructionGenerator) -> TypeInfo { - TypeInfo::Float64 - } - pub fn is_return_reference(&self, _instructions: &InstructionGenerator) -> bool { - false - } -} - -/// for string literal +/// "string literal" #[derive(Debug, Clone)] pub struct ExprString { pub value: String, } -impl ExprString { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - // store string to global text section - let offset = instructions.text_section.len(); // <-- this will be absolute address - - let mut null_terminated = self.value.clone(); - null_terminated.push('\0'); - instructions - .text_section - .append(&mut null_terminated.as_bytes().to_vec()); - // put its address to register0 - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Value(VariableData::UInt64(offset as u64)), - operand_to: Operand::Register(0), - })); - } - pub fn get_typeinfo(&self, _instructions: &InstructionGenerator) -> TypeInfo { - TypeInfo::Pointer(Box::new(TypeInfo::Const(Box::new(TypeInfo::Int8)))) - } - pub fn is_return_reference(&self, _instructions: &InstructionGenerator) -> bool { - false - } -} - -/// src[index] +/// src.member #[derive(Debug, Clone)] -pub struct ExprPostBracket { +pub struct ExprMember { pub src: Box, - pub index: Box, -} -impl ExprPostBracket { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - match self.src.get_typeinfo(instructions).remove_const() { - TypeInfo::Array(_, _) => {} - TypeInfo::Pointer(_) => {} - _ => panic!("Bracket is only available at array or pointer type"), - } - self.index.emit(instructions); - if self.index.is_return_reference(instructions) { - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Derefed(0, 0), - })); - } else { - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Register(0), - })); - } - // register0 = src - self.src.emit(instructions); - if self.src.is_return_reference(instructions) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(0, 0), - operand_to: Operand::Register(0), - })); - } - // register1 = index - instructions.push(Instruction::PopStack(PopStack { - operand: Operand::Register(1), - })); - - match self.src.get_typeinfo(instructions).remove_const() { - TypeInfo::Array(t, _) => { - let move_size = t.number_of_primitives(); - instructions.push(Instruction::MulAssign(MulAssign { - lhs: Operand::Register(1), - rhs: Operand::Value(VariableData::UInt64(move_size as u64)), - })); - instructions.push(Instruction::AddAssign(AddAssign { - lhs: Operand::Register(0), - rhs: Operand::Register(1), - })); - } - TypeInfo::Pointer(t) => { - let move_size = t.number_of_primitives(); - instructions.push(Instruction::MulAssign(MulAssign { - lhs: Operand::Register(1), - rhs: Operand::Value(VariableData::UInt64(move_size as u64)), - })); - instructions.push(Instruction::AddAssign(AddAssign { - lhs: Operand::Register(0), - rhs: Operand::Register(1), - })); - } - _ => panic!("Bracket is only available at array or pointer type"), - } - } - pub fn get_typeinfo(&self, instructions: &InstructionGenerator) -> TypeInfo { - let src_type = self.src.get_typeinfo(instructions); - match src_type.remove_const() { - TypeInfo::Array(t, _) => { - if src_type.is_const() { - t.add_const() - } else { - *t - } - } - TypeInfo::Pointer(t) => *t, - _ => panic!("Bracket is only available at array or pointer type"), - } - } - pub fn is_return_reference(&self, _instructions: &InstructionGenerator) -> bool { - true - } + pub member: String, } - -/// src( args... ) +// src->member #[derive(Debug, Clone)] -pub struct ExprPostParen { +pub struct ExprArrow { pub src: Box, - pub args: Vec, -} -// currently only for function call -impl ExprPostParen { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - let identifier = match &*self.src { - Expression::PrimaryIdentifier(identifier) => identifier, - _ => panic!("FunctionCall must be called on `Identifier`"), - }; - let name = identifier.name.clone(); - - // check if it is a built-in function, print or print_str - if &name == "print" { - for arg in self.args.iter().rev() { - arg.emit(instructions); - if arg.is_return_reference(instructions) { - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Derefed(0, 0), - })); - } else { - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Register(0), - })); - } - } - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Value(VariableData::UInt64(self.args.len() as u64)), - })); - instructions.push(Instruction::Print(Print {})); - } else if &name == "print_str" { - if self.args.len() != 1 { - panic!( - "print_str expects 1 argument, but {} were provided", - self.args.len() - ); - } - self.args[0].emit(instructions); - if self.args[0].is_return_reference(instructions) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(0, 0), - operand_to: Operand::Register(0), - })); - } - instructions.push(Instruction::PrintStr(PrintStr { - str: Operand::Register(0), - })); - } else { - let funcdata = instructions - .functions - .get(&name) - .expect(format!("Function not found : {}", &name).as_str()) - .clone(); - if funcdata.params.len() != self.args.len() { - panic!( - "Function {} expects {} arguments, but {} were provided", - name, - funcdata.params.len(), - self.args.len() - ); - } - - // push arguments to stack - for param in self.args.iter().rev() { - param.emit(instructions); - if param.is_return_reference(instructions) { - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Derefed(0, 0), - })); - } else { - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Register(0), - })); - } - } - - // call function - instructions.push(Instruction::Call(Call { - label: name.clone(), - })); - - // pop arguments from stack - instructions.push(Instruction::SubAssign(SubAssign { - lhs: Operand::Register(STACK_POINTER_REGISTER), - rhs: Operand::Value(VariableData::UInt64(funcdata.params.len() as u64)), - })); - } - } - pub fn get_typeinfo(&self, instructions: &InstructionGenerator) -> TypeInfo { - let identifier = match &*self.src { - Expression::PrimaryIdentifier(identifier) => identifier, - _ => panic!("FunctionCall must be called on `Identifier`"), - }; - let name = identifier.name.clone(); - let funcdata = &instructions - .functions - .get(&name) - .expect(format!("Function not found : {}", &name).as_str()); - instructions - .get_true_typeinfo(&funcdata.return_type) - .clone() - } - pub fn is_return_reference(&self, _instructions: &InstructionGenerator) -> bool { - false - } + pub member: String, } - -/// src++ +/// src[index] #[derive(Debug, Clone)] -pub struct ExprPostIncrement { +pub struct ExprBracket { pub src: Box, -} -impl ExprPostIncrement { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - if self.src.is_return_reference(instructions) == false { - panic!("PostIncrement on non-lhs"); - } - if self.src.get_typeinfo(instructions).is_const() { - panic!("PostIncrement on const variable"); - } - self.src.emit(instructions); - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Register(0), - operand_to: Operand::Register(1), - })); - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(1, 0), - operand_to: Operand::Register(0), - })); - if let TypeInfo::Pointer(t) = self.src.get_typeinfo(instructions) { - let move_size = t.number_of_primitives(); - instructions.push(Instruction::AddAssign(AddAssign { - lhs: Operand::Derefed(1, 0), - rhs: Operand::Value(VariableData::UInt64(move_size as u64)), - })); - } else { - instructions.push(Instruction::AddAssign(AddAssign { - lhs: Operand::Derefed(1, 0), - rhs: Operand::Value(VariableData::UInt8(1)), - })); - } - } - pub fn get_typeinfo(&self, instructions: &InstructionGenerator) -> TypeInfo { - self.src.get_typeinfo(instructions) - } - pub fn is_return_reference(&self, _instructions: &InstructionGenerator) -> bool { - false - } + pub index: Box, } -/// src-- +/// src( args... ) #[derive(Debug, Clone)] -pub struct ExprPostDecrement { +pub struct ExprParen { pub src: Box, + pub args: Vec, } -impl ExprPostDecrement { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - if self.src.is_return_reference(instructions) == false { - panic!("PostDecrement on non-lhs"); - } - if self.src.get_typeinfo(instructions).is_const() { - panic!("PostDecrement on const variable"); - } - self.src.emit(instructions); - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Register(0), - operand_to: Operand::Register(1), - })); - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(1, 0), - operand_to: Operand::Register(0), - })); - - if let TypeInfo::Pointer(t) = self.src.get_typeinfo(instructions) { - let move_size = t.number_of_primitives(); - instructions.push(Instruction::SubAssign(SubAssign { - lhs: Operand::Derefed(1, 0), - rhs: Operand::Value(VariableData::UInt64(move_size as u64)), - })); - } else { - instructions.push(Instruction::SubAssign(SubAssign { - lhs: Operand::Derefed(1, 0), - rhs: Operand::Value(VariableData::UInt8(1)), - })); - } - } - pub fn get_typeinfo(&self, instructions: &InstructionGenerator) -> TypeInfo { - self.src.get_typeinfo(instructions) - } - pub fn is_return_reference(&self, _instructions: &InstructionGenerator) -> bool { - false - } -} - /// (typeinfo)src #[derive(Debug, Clone)] pub struct ExprCast { pub src: Box, - pub typeinfo: TypeInfo, -} -impl ExprCast { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - self.src.emit(instructions); - if self.src.is_return_reference(instructions) { - instructions.push(Instruction::Cast(Cast { - info: instructions - .get_true_typeinfo(&self.typeinfo) - .remove_const(), - operand_from: Operand::Derefed(0, 0), - operand_to: Operand::Register(0), - })); - } else { - instructions.push(Instruction::Cast(Cast { - info: instructions - .get_true_typeinfo(&self.typeinfo) - .remove_const(), - operand_from: Operand::Register(0), - operand_to: Operand::Register(0), - })); - } - } - pub fn get_typeinfo(&self, instructions: &InstructionGenerator) -> TypeInfo { - instructions - .get_true_typeinfo(&self.typeinfo) - .remove_const() - } - pub fn is_return_reference(&self, _instructions: &InstructionGenerator) -> bool { - false - } + pub typename: declarator::Typename, } - -/// sizeof(typeinfo) +/// sizeof(type) #[derive(Debug, Clone)] pub struct ExprSizeOfType { - pub typeinfo: TypeInfo, -} -impl ExprSizeOfType { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Value(VariableData::UInt64(self.typeinfo.sizeof() as u64)), - operand_to: Operand::Register(0), - })); - } - pub fn get_constant_i64(&self) -> Result { - Ok(self.typeinfo.sizeof() as i64) - } - pub fn get_typeinfo(&self, _instructions: &InstructionGenerator) -> TypeInfo { - TypeInfo::UInt64 - } - pub fn is_return_reference(&self, _instructions: &InstructionGenerator) -> bool { - false - } + pub typename: declarator::Typename, } - /// sizeof(expr) #[derive(Debug, Clone)] pub struct ExprSizeOfExpr { pub expr: Box, } -impl ExprSizeOfExpr { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Value(VariableData::UInt64( - self.expr.get_typeinfo(instructions).sizeof() as u64, - )), - operand_to: Operand::Register(0), - })); - } - pub fn get_typeinfo(&self, _instructions: &InstructionGenerator) -> TypeInfo { - TypeInfo::UInt64 - } - pub fn is_return_reference(&self, _instructions: &InstructionGenerator) -> bool { - false - } +#[derive(Debug, Clone)] +pub struct ExprConditional { + pub cond: Box, + pub then_expr: Box, + pub else_expr: Box, } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum UnaryOperator { +#[derive(Debug, Clone)] +pub struct ExprUnary { + pub op: ExprUnaryOperator, + pub src: Box, +} +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum ExprUnaryOperator { Plus, Minus, LogicalNot, BitwiseNot, Dereference, AddressOf, - Increment, - Decrement, -} -#[derive(Debug, Clone)] -pub struct ExprUnary { - pub op: UnaryOperator, - pub src: Box, -} -impl ExprUnary { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - self.src.emit(instructions); - - let src_type = self.src.get_typeinfo(instructions); - - match self.op { - UnaryOperator::Plus => { - match src_type.remove_const() { - TypeInfo::Int8 - | TypeInfo::UInt8 - | TypeInfo::Int16 - | TypeInfo::UInt16 - | TypeInfo::Int32 - | TypeInfo::UInt32 - | TypeInfo::Int64 - | TypeInfo::UInt64 - | TypeInfo::Float32 - | TypeInfo::Float64 - | TypeInfo::Pointer(_) - | TypeInfo::Array(_, _) => { - if self.src.is_return_reference(instructions) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(0, 0), - operand_to: Operand::Register(0), - })); - } - } - _ => panic!( - "Unary Plus not implemented for {:?}", - self.src.get_typeinfo(instructions) - ), - }; - } - UnaryOperator::Minus => match src_type.remove_const() { - TypeInfo::Int8 - | TypeInfo::UInt8 - | TypeInfo::Int16 - | TypeInfo::UInt16 - | TypeInfo::Int32 - | TypeInfo::UInt32 - | TypeInfo::Int64 - | TypeInfo::UInt64 - | TypeInfo::Float32 - | TypeInfo::Float64 - | TypeInfo::Pointer(_) - | TypeInfo::Array(_, _) => { - if self.src.is_return_reference(instructions) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(0, 0), - operand_to: Operand::Register(0), - })); - } - instructions.push(Instruction::Negate(Negate { - operand: Operand::Register(0), - })); - } - _ => panic!( - "Unary Minus not implemented for {:?}", - self.src.get_typeinfo(instructions) - ), - }, - UnaryOperator::LogicalNot => { - match src_type.remove_const() { - TypeInfo::Int8 - | TypeInfo::UInt8 - | TypeInfo::Int16 - | TypeInfo::UInt16 - | TypeInfo::Int32 - | TypeInfo::UInt32 - | TypeInfo::Int64 - | TypeInfo::UInt64 - | TypeInfo::Pointer(_) - | TypeInfo::Array(_, _) => { - if self.src.is_return_reference(instructions) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(0, 0), - operand_to: Operand::Register(0), - })); - } - instructions.push(Instruction::LogicalNot(LogicalNot { - operand: Operand::Register(0), - })); - } - _ => panic!( - "Unary LogicalNot not implemented for {:?}", - self.src.get_typeinfo(instructions) - ), - }; - } - UnaryOperator::BitwiseNot => { - match src_type.remove_const() { - TypeInfo::Int8 - | TypeInfo::UInt8 - | TypeInfo::Int16 - | TypeInfo::UInt16 - | TypeInfo::Int32 - | TypeInfo::UInt32 - | TypeInfo::Int64 - | TypeInfo::UInt64 => { - if self.src.is_return_reference(instructions) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(0, 0), - operand_to: Operand::Register(0), - })); - } - instructions.push(Instruction::BitwiseNot(BitwiseNot { - operand: Operand::Register(0), - })); - } - _ => panic!( - "Unary BitwiseNot not implemented for {:?}", - self.src.get_typeinfo(instructions) - ), - }; - } - UnaryOperator::Dereference => { - if let TypeInfo::Pointer(_) = src_type.remove_const() { - if self.src.is_return_reference(instructions) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(0, 0), - operand_to: Operand::Register(0), - })); - } else { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Register(0), - operand_to: Operand::Register(0), - })); - } - } else { - panic!( - "Dereference on non-pointer type :{:?}", - self.src.get_typeinfo(instructions) - ); - } - } - UnaryOperator::AddressOf => { - if self.src.is_return_reference(instructions) == false { - panic!("AddressOf on non-reference"); - } - } - UnaryOperator::Increment => { - if src_type.is_const() { - panic!("Increment on const variable"); - } - match src_type { - TypeInfo::Int8 - | TypeInfo::UInt8 - | TypeInfo::Int16 - | TypeInfo::UInt16 - | TypeInfo::Int32 - | TypeInfo::UInt32 - | TypeInfo::Int64 - | TypeInfo::UInt64 => { - if self.src.is_return_reference(instructions) { - instructions.push(Instruction::AddAssign(AddAssign { - lhs: Operand::Derefed(0, 0), - rhs: Operand::Value(VariableData::UInt8(1)), - })); - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(0, 0), - operand_to: Operand::Register(0), - })); - } else { - panic!("Increment on non-reference"); - } - } - TypeInfo::Pointer(t) => { - let move_size = t.number_of_primitives(); - if self.src.is_return_reference(instructions) { - instructions.push(Instruction::AddAssign(AddAssign { - lhs: Operand::Derefed(0, 0), - rhs: Operand::Value(VariableData::UInt64(move_size as u64)), - })); - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(0, 0), - operand_to: Operand::Register(0), - })); - } else { - panic!("Increment on non-reference"); - } - } - _ => panic!( - "Unary Increment not implemented for {:?}", - self.src.get_typeinfo(instructions) - ), - }; - } - UnaryOperator::Decrement => { - if src_type.is_const() { - panic!("Decrement on const variable"); - } - match src_type { - TypeInfo::Int8 - | TypeInfo::UInt8 - | TypeInfo::Int16 - | TypeInfo::UInt16 - | TypeInfo::Int32 - | TypeInfo::UInt32 - | TypeInfo::Int64 - | TypeInfo::UInt64 => { - if self.src.is_return_reference(instructions) { - instructions.push(Instruction::SubAssign(SubAssign { - lhs: Operand::Derefed(0, 0), - rhs: Operand::Value(VariableData::UInt8(1)), - })); - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(0, 0), - operand_to: Operand::Register(0), - })); - } else { - panic!("Decrement on non-reference"); - } - } - TypeInfo::Pointer(t) => { - let move_size = t.number_of_primitives(); - if self.src.is_return_reference(instructions) { - instructions.push(Instruction::SubAssign(SubAssign { - lhs: Operand::Derefed(0, 0), - rhs: Operand::Value(VariableData::UInt64(move_size as u64)), - })); - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(0, 0), - operand_to: Operand::Register(0), - })); - } else { - panic!("Decrement on non-reference"); - } - } - _ => panic!( - "Unary Decrement not implemented for {:?}", - self.src.get_typeinfo(instructions) - ), - }; - } - } - } - pub fn get_typeinfo(&self, instructions: &InstructionGenerator) -> TypeInfo { - let srctype = self.src.get_typeinfo(instructions); - match self.op { - UnaryOperator::Plus => srctype.remove_const(), - UnaryOperator::Minus => match srctype.remove_const() { - TypeInfo::Int8 => TypeInfo::Int8, - TypeInfo::UInt8 => TypeInfo::Int8, - TypeInfo::Int16 => TypeInfo::Int16, - TypeInfo::UInt16 => TypeInfo::Int16, - TypeInfo::Int32 => TypeInfo::Int32, - TypeInfo::UInt32 => TypeInfo::Int32, - TypeInfo::Int64 => TypeInfo::Int64, - TypeInfo::UInt64 => TypeInfo::Int64, - TypeInfo::Float32 => TypeInfo::Float32, - TypeInfo::Float64 => TypeInfo::Float64, - TypeInfo::Pointer(t) => TypeInfo::Pointer(t), - TypeInfo::Array(t, _) => TypeInfo::Pointer(t), - _ => panic!("Unary Minus not implemented for {:?}", srctype), - }, - UnaryOperator::LogicalNot => TypeInfo::UInt8, - UnaryOperator::BitwiseNot => match srctype.remove_const() { - TypeInfo::Int8 => TypeInfo::Int8, - TypeInfo::UInt8 => TypeInfo::Int8, - TypeInfo::Int16 => TypeInfo::Int16, - TypeInfo::UInt16 => TypeInfo::Int16, - TypeInfo::Int32 => TypeInfo::Int32, - TypeInfo::UInt32 => TypeInfo::Int32, - TypeInfo::Int64 => TypeInfo::Int64, - TypeInfo::UInt64 => TypeInfo::Int64, - _ => panic!("BitwiseNot not implemented for {:?}", srctype), - }, - UnaryOperator::Dereference => { - if let TypeInfo::Pointer(t) = srctype.remove_const() { - instructions.get_true_typeinfo(t.as_ref()).clone() - } else { - panic!("Dereference on non-pointer type"); - } - } - UnaryOperator::AddressOf => { - if self.src.is_return_reference(instructions) == false { - panic!("AddressOf on non-reference"); - } - TypeInfo::Pointer(Box::new(srctype)) - } - UnaryOperator::Increment | UnaryOperator::Decrement => srctype.remove_const(), - } - } - pub fn is_return_reference(&self, _instructions: &InstructionGenerator) -> bool { - match self.op { - UnaryOperator::Dereference => true, - _ => false, - } - } + IncrementPre, + DecrementPre, + IncrementPost, + DecrementPost, } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum BinaryOperator { +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum ExprBinaryOperator { Add, Sub, Mul, @@ -1171,1340 +174,17 @@ pub enum BinaryOperator { BitwiseXorAssign, ShiftLeftAssign, ShiftRightAssign, + Comma, } -/// for logical and, or #[derive(Debug, Clone)] -pub struct ExprLogicalBinary { - pub op: BinaryOperator, +pub struct ExprBinary { + pub op: ExprBinaryOperator, pub lhs: Box, pub rhs: Box, } -impl ExprLogicalBinary { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - let lhs_type = self.lhs.get_typeinfo(instructions); - let rhs_type = self.rhs.get_typeinfo(instructions); - match lhs_type.remove_const() { - TypeInfo::UInt8 - | TypeInfo::Int8 - | TypeInfo::UInt16 - | TypeInfo::Int16 - | TypeInfo::UInt32 - | TypeInfo::Int32 - | TypeInfo::UInt64 - | TypeInfo::Int64 - | TypeInfo::Pointer(_) - | TypeInfo::Array(_, _) => {} - _ => panic!( - "{:?} on non-integral type (LHS:{:?})", - self.op, - self.lhs.get_typeinfo(instructions) - ), - } - match rhs_type.remove_const() { - TypeInfo::UInt8 - | TypeInfo::Int8 - | TypeInfo::UInt16 - | TypeInfo::Int16 - | TypeInfo::UInt32 - | TypeInfo::Int32 - | TypeInfo::UInt64 - | TypeInfo::Int64 - | TypeInfo::Pointer(_) - | TypeInfo::Array(_, _) => {} - _ => panic!( - "{:?} on non-integral type (RHS:{:?})", - self.op, - self.rhs.get_typeinfo(instructions) - ), - } - - self.lhs.emit(instructions); - if self.lhs.is_return_reference(instructions) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(0, 0), - operand_to: Operand::Register(0), - })); - } - match self.op { - BinaryOperator::LogicalAnd => { - let zero_label = instructions.get_unique_label(); - let end_label = instructions.get_unique_label(); - instructions.push(Instruction::JumpZero(JumpZero { - operand_cond: Operand::Register(0), - label: zero_label.clone(), - })); - - // lhs is true here - // eval rhs - self.rhs.emit(instructions); - if self.rhs.is_return_reference(instructions) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(0, 0), - operand_to: Operand::Register(0), - })); - } - instructions.push(Instruction::JumpZero(JumpZero { - label: zero_label.clone(), - operand_cond: Operand::Register(0), - })); - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Value(VariableData::UInt8(1)), - operand_to: Operand::Register(0), - })); - instructions.push(Instruction::Jump(Jump { - label: end_label.clone(), - })); - - instructions.set_label(&zero_label); - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Value(VariableData::UInt8(0)), - operand_to: Operand::Register(0), - })); - instructions.set_label(&end_label); - } - BinaryOperator::LogicalOr => { - let one_label = instructions.get_unique_label(); - let end_label = instructions.get_unique_label(); - instructions.push(Instruction::JumpNonZero(JumpNonZero { - operand_cond: Operand::Register(0), - label: one_label.clone(), - })); - - // lhs is false here - // eval rhs - self.rhs.emit(instructions); - if self.rhs.is_return_reference(instructions) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(0, 0), - operand_to: Operand::Register(0), - })); - } - instructions.push(Instruction::JumpNonZero(JumpNonZero { - label: one_label.clone(), - operand_cond: Operand::Register(0), - })); - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Value(VariableData::UInt8(0)), - operand_to: Operand::Register(0), - })); - instructions.push(Instruction::Jump(Jump { - label: end_label.clone(), - })); - - instructions.set_label(&one_label); - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Value(VariableData::UInt8(1)), - operand_to: Operand::Register(0), - })); - instructions.set_label(&end_label); - } - _ => { - panic!( - "Invalid operator for LogicalBinaryExpression: {:?}", - self.op - ); - } - } - } - pub fn is_return_reference(&self, _instructions: &InstructionGenerator) -> bool { - false - } - pub fn get_typeinfo(&self, instructions: &InstructionGenerator) -> TypeInfo { - match self.lhs.get_typeinfo(instructions).remove_const() { - TypeInfo::UInt8 - | TypeInfo::Int8 - | TypeInfo::UInt16 - | TypeInfo::Int16 - | TypeInfo::UInt32 - | TypeInfo::Int32 - | TypeInfo::UInt64 - | TypeInfo::Int64 - | TypeInfo::Pointer(_) - | TypeInfo::Array(_, _) => {} - _ => panic!( - "{:?} on non-integral type (LHS:{:?})", - self.op, - self.lhs.get_typeinfo(instructions) - ), - } - match self.rhs.get_typeinfo(instructions).remove_const() { - TypeInfo::UInt8 - | TypeInfo::Int8 - | TypeInfo::UInt16 - | TypeInfo::Int16 - | TypeInfo::UInt32 - | TypeInfo::Int32 - | TypeInfo::UInt64 - | TypeInfo::Int64 - | TypeInfo::Pointer(_) - | TypeInfo::Array(_, _) => {} - _ => panic!( - "{:?} on non-integral type (RHS:{:?})", - self.op, - self.rhs.get_typeinfo(instructions) - ), - } - - TypeInfo::UInt8 - } -} - -#[derive(Debug, Clone)] -pub struct ExprComparison { - pub op: BinaryOperator, - pub lhs: Box, - pub rhs: Box, -} -impl ExprComparison { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - match self.lhs.get_typeinfo(instructions).remove_const() { - TypeInfo::UInt8 - | TypeInfo::Int8 - | TypeInfo::UInt16 - | TypeInfo::Int16 - | TypeInfo::UInt32 - | TypeInfo::Int32 - | TypeInfo::UInt64 - | TypeInfo::Int64 - | TypeInfo::Float32 - | TypeInfo::Float64 - | TypeInfo::Pointer(_) - | TypeInfo::Array(_, _) => {} - _ => panic!( - "{:?} on non-numeric type (LHS:{:?})", - self.op, - self.lhs.get_typeinfo(instructions) - ), - } - match self.rhs.get_typeinfo(instructions).remove_const() { - TypeInfo::UInt8 - | TypeInfo::Int8 - | TypeInfo::UInt16 - | TypeInfo::Int16 - | TypeInfo::UInt32 - | TypeInfo::Int32 - | TypeInfo::UInt64 - | TypeInfo::Int64 - | TypeInfo::Float32 - | TypeInfo::Float64 - | TypeInfo::Pointer(_) - | TypeInfo::Array(_, _) => {} - _ => panic!( - "{:?} on non-numeric type (RHS:{:?})", - self.op, - self.rhs.get_typeinfo(instructions) - ), - } - - // eval lhs and push to stack - self.lhs.emit(instructions); - if self.lhs.is_return_reference(instructions) { - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Derefed(0, 0), - })); - } else { - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Register(0), - })); - } - - // eval rhs - self.rhs.emit(instructions); - if self.rhs.is_return_reference(instructions) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(0, 0), - operand_to: Operand::Register(0), - })); - } - - // pop lhs from stack - instructions.push(Instruction::PopStack(PopStack { - operand: Operand::Register(1), - })); - - let lhs_register = Operand::Register(1); - let rhs_register = Operand::Register(0); - - match self.op { - BinaryOperator::LessThan => { - // lhs < rhs - instructions.push(Instruction::LessThan(LessThan { - lhs: lhs_register, - rhs: rhs_register, - to: Operand::Register(0), - })); - } - BinaryOperator::GreaterThan => { - // lhs > rhs - instructions.push(Instruction::LessThan(LessThan { - lhs: rhs_register, - rhs: lhs_register, - to: Operand::Register(0), - })); - } - BinaryOperator::LessThanOrEqual => { - // lhs <= rhs - // !( lhs > rhs ) - instructions.push(Instruction::LessThan(LessThan { - lhs: rhs_register, - rhs: lhs_register, - to: Operand::Register(0), - })); - instructions.push(Instruction::LogicalNot(LogicalNot { - operand: Operand::Register(0), - })); - } - BinaryOperator::GreaterThanOrEqual => { - // lhs >= rhs - // !( lhs < rhs ) - instructions.push(Instruction::LessThan(LessThan { - lhs: lhs_register, - rhs: rhs_register, - to: Operand::Register(0), - })); - instructions.push(Instruction::LogicalNot(LogicalNot { - operand: Operand::Register(0), - })); - } - BinaryOperator::Equal => { - // lhs == rhs - instructions.push(Instruction::Equal(Equal { - lhs: lhs_register, - rhs: rhs_register, - to: Operand::Register(0), - })); - } - BinaryOperator::NotEqual => { - // !(lhs == rhs ) - instructions.push(Instruction::Equal(Equal { - lhs: lhs_register, - rhs: rhs_register, - to: Operand::Register(0), - })); - instructions.push(Instruction::LogicalNot(LogicalNot { - operand: Operand::Register(0), - })); - } - _ => panic!("Invalid operator for ComparisonExpression: {:?}", self.op), - } - } - pub fn get_typeinfo(&self, instructions: &InstructionGenerator) -> TypeInfo { - match self.lhs.get_typeinfo(instructions).remove_const() { - TypeInfo::UInt8 - | TypeInfo::Int8 - | TypeInfo::UInt16 - | TypeInfo::Int16 - | TypeInfo::UInt32 - | TypeInfo::Int32 - | TypeInfo::UInt64 - | TypeInfo::Int64 - | TypeInfo::Float32 - | TypeInfo::Float64 - | TypeInfo::Pointer(_) - | TypeInfo::Array(_, _) => {} - _ => panic!( - "{:?} on non-int type (LHS:{:?})", - self.op, - self.lhs.get_typeinfo(instructions) - ), - } - match self.rhs.get_typeinfo(instructions).remove_const() { - TypeInfo::UInt8 - | TypeInfo::Int8 - | TypeInfo::UInt16 - | TypeInfo::Int16 - | TypeInfo::UInt32 - | TypeInfo::Int32 - | TypeInfo::UInt64 - | TypeInfo::Int64 - | TypeInfo::Float32 - | TypeInfo::Float64 - | TypeInfo::Pointer(_) - | TypeInfo::Array(_, _) => {} - _ => panic!( - "{:?} on non-int type (RHS:{:?})", - self.op, - self.rhs.get_typeinfo(instructions) - ), - } - - TypeInfo::UInt8 - } - pub fn is_return_reference(&self, _instructions: &InstructionGenerator) -> bool { - false - } -} -// lhs = rhs -#[derive(Debug, Clone)] -pub struct ExprAssign { - pub lhs: Box, - pub rhs: Box, -} -impl ExprAssign { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - let lhs_type = self.lhs.get_typeinfo(instructions); - // check lhs is not const - if lhs_type.is_const() { - panic!("Assign to const variable"); - } - // check lhs is reference - if self.lhs.is_return_reference(instructions) == false { - panic!("Assign on non-reference"); - } - - let rhs_type = self.rhs.get_typeinfo(instructions); - - // check if it is non-numeric <-> non-numeric assignment - if let TypeInfo::Struct(lhs_type) = lhs_type { - if let TypeInfo::Struct(rhs_type) = rhs_type.remove_const() { - if &lhs_type != &rhs_type { - panic!( - "Struct assignment with different types: {:?} = {:?}", - lhs_type, rhs_type - ); - } - // struct = struct assignment - self.rhs.emit(instructions); - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Register(0), - })); - self.lhs.emit(instructions); - instructions.push(Instruction::PopStack(PopStack { - operand: Operand::Register(1), - })); - - let count = lhs_type.number_of_primitives(); - instructions.push(Instruction::AssignStruct(AssignStruct { - count, - lhs: Operand::Register(0), - rhs: Operand::Register(1), - })); - } else { - // struct = other assignment; panic - panic!( - "Struct assignment with non-struct type: {:?} = {:?}", - lhs_type, - self.rhs.get_typeinfo(instructions) - ); - } - } else { - // normal assignment - - if self.lhs.is_return_reference(instructions) == false { - panic!("Assign on non-reference"); - } - self.rhs.emit(instructions); - if self.rhs.is_return_reference(instructions) { - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Derefed(0, 0), - })); - } else { - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Register(0), - })); - } - self.lhs.emit(instructions); - instructions.push(Instruction::PopStack(PopStack { - operand: Operand::Register(1), - })); - instructions.push(Instruction::Assign(Assign { - lhs_type: self.lhs.get_typeinfo(instructions), - lhs: Operand::Derefed(0, 0), - rhs: Operand::Register(1), - })); - } - } - pub fn is_return_reference(&self, instructions: &InstructionGenerator) -> bool { - self.lhs.is_return_reference(instructions) - } - pub fn get_typeinfo(&self, instructions: &InstructionGenerator) -> TypeInfo { - self.lhs.get_typeinfo(instructions) - } -} - -// += -= *= /= %= -// <<= >>= &= |= ^= -#[derive(Debug, Clone)] -pub struct ExprAssignOp { - pub op: BinaryOperator, - pub lhs: Box, - pub rhs: Box, -} -impl ExprAssignOp { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - let lhs_type = self.lhs.get_typeinfo(instructions); - if self.lhs.is_return_reference(instructions) == false { - panic!("{:?} on non-reference", self.op); - } - if lhs_type.is_const() { - panic!("{:?} on const variable", self.op); - } - - self.rhs.emit(instructions); - if self.rhs.is_return_reference(instructions) { - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Derefed(0, 0), - })); - } else { - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Register(0), - })); - } - self.lhs.emit(instructions); - instructions.push(Instruction::PopStack(PopStack { - operand: Operand::Register(1), - })); - match self.op { - BinaryOperator::AddAssign => { - if let TypeInfo::Pointer(t) = lhs_type { - let move_size = t.number_of_primitives(); - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Value(VariableData::Int64(move_size as i64)), - operand_to: Operand::Register(2), - })); - instructions.push(Instruction::MulAssign(MulAssign { - lhs: Operand::Register(2), - rhs: Operand::Register(1), - })); - instructions.push(Instruction::AddAssign(AddAssign { - lhs: Operand::Derefed(0, 0), - rhs: Operand::Register(2), - })); - } else { - instructions.push(Instruction::AddAssign(AddAssign { - lhs: Operand::Derefed(0, 0), - rhs: Operand::Register(1), - })); - } - } - BinaryOperator::SubAssign => { - if let TypeInfo::Pointer(t) = lhs_type { - let move_size = t.number_of_primitives(); - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Value(VariableData::Int64(move_size as i64)), - operand_to: Operand::Register(2), - })); - instructions.push(Instruction::MulAssign(MulAssign { - lhs: Operand::Register(2), - rhs: Operand::Register(1), - })); - instructions.push(Instruction::SubAssign(SubAssign { - lhs: Operand::Derefed(0, 0), - rhs: Operand::Register(2), - })); - } else { - instructions.push(Instruction::SubAssign(SubAssign { - lhs: Operand::Derefed(0, 0), - rhs: Operand::Register(1), - })); - } - } - BinaryOperator::MulAssign => { - instructions.push(Instruction::MulAssign(MulAssign { - lhs: Operand::Derefed(0, 0), - rhs: Operand::Register(1), - })); - } - BinaryOperator::DivAssign => { - instructions.push(Instruction::DivAssign(DivAssign { - lhs: Operand::Derefed(0, 0), - rhs: Operand::Register(1), - })); - } - BinaryOperator::ModAssign => { - instructions.push(Instruction::ModAssign(ModAssign { - lhs: Operand::Derefed(0, 0), - rhs: Operand::Register(1), - })); - } - BinaryOperator::ShiftLeftAssign => { - instructions.push(Instruction::ShiftLeftAssign(ShiftLeftAssign { - lhs: Operand::Derefed(0, 0), - rhs: Operand::Register(1), - })); - } - BinaryOperator::ShiftRightAssign => { - instructions.push(Instruction::ShiftRightAssign(ShiftRightAssign { - lhs: Operand::Derefed(0, 0), - rhs: Operand::Register(1), - })); - } - BinaryOperator::BitwiseAndAssign => { - instructions.push(Instruction::BitwiseAndAssign(BitwiseAndAssign { - lhs: Operand::Derefed(0, 0), - rhs: Operand::Register(1), - })); - } - BinaryOperator::BitwiseOrAssign => { - instructions.push(Instruction::BitwiseOrAssign(BitwiseOrAssign { - lhs: Operand::Derefed(0, 0), - rhs: Operand::Register(1), - })); - } - BinaryOperator::BitwiseXorAssign => { - instructions.push(Instruction::BitwiseXorAssign(BitwiseXorAssign { - lhs: Operand::Derefed(0, 0), - rhs: Operand::Register(1), - })); - } - _ => panic!("Invalid operator for AssignExpression: {:?}", self.op), - } - } - pub fn is_return_reference(&self, instructions: &InstructionGenerator) -> bool { - self.lhs.is_return_reference(instructions) - } - pub fn get_typeinfo(&self, instructions: &InstructionGenerator) -> TypeInfo { - self.lhs.get_typeinfo(instructions) - } -} - -#[derive(Debug, Clone)] -pub struct ExprAdditive { - pub op: BinaryOperator, - pub lhs: Box, - pub rhs: Box, -} -impl ExprAdditive { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - // for type-check panic - self.get_typeinfo(instructions); - - self.rhs.emit(instructions); - if self.rhs.is_return_reference(instructions) { - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Derefed(0, 0), - })); - } else { - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Register(0), - })); - } - - self.lhs.emit(instructions); - if self.lhs.is_return_reference(instructions) { - instructions.push(Instruction::Assign(Assign { - lhs_type: self.get_typeinfo(instructions), - lhs: Operand::Register(0), - rhs: Operand::Derefed(0, 0), - })); - } else { - instructions.push(Instruction::Assign(Assign { - lhs_type: self.get_typeinfo(instructions), - lhs: Operand::Register(0), - rhs: Operand::Register(0), - })); - } - instructions.push(Instruction::PopStack(PopStack { - operand: Operand::Register(1), - })); - - // pointer arithmetic - if let TypeInfo::Pointer(t) = self.lhs.get_typeinfo(instructions).remove_const() { - let move_size = t.number_of_primitives(); - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Value(VariableData::Int64(move_size as i64)), - operand_to: Operand::Register(2), - })); - instructions.push(Instruction::MulAssign(MulAssign { - lhs: Operand::Register(2), - rhs: Operand::Register(1), - })); - - match self.op { - BinaryOperator::Add => { - instructions.push(Instruction::AddAssign(AddAssign { - lhs: Operand::Register(0), - rhs: Operand::Register(2), - })); - } - BinaryOperator::Sub => { - instructions.push(Instruction::SubAssign(SubAssign { - lhs: Operand::Register(0), - rhs: Operand::Register(2), - })); - } - _ => panic!("Invalid operator for AdditiveExpression: {:?}", self.op), - } - } else if let TypeInfo::Array(t, _) = self.lhs.get_typeinfo(instructions).remove_const() { - let move_size = t.number_of_primitives(); - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Value(VariableData::Int64(move_size as i64)), - operand_to: Operand::Register(2), - })); - instructions.push(Instruction::MulAssign(MulAssign { - lhs: Operand::Register(2), - rhs: Operand::Register(1), - })); - - match self.op { - BinaryOperator::Add => { - instructions.push(Instruction::AddAssign(AddAssign { - lhs: Operand::Register(0), - rhs: Operand::Register(2), - })); - } - BinaryOperator::Sub => { - instructions.push(Instruction::SubAssign(SubAssign { - lhs: Operand::Register(0), - rhs: Operand::Register(2), - })); - } - _ => panic!("Invalid operator for AdditiveExpression: {:?}", self.op), - } - } else { - match self.op { - BinaryOperator::Add => { - instructions.push(Instruction::AddAssign(AddAssign { - lhs: Operand::Register(0), - rhs: Operand::Register(1), - })); - } - BinaryOperator::Sub => { - instructions.push(Instruction::SubAssign(SubAssign { - lhs: Operand::Register(0), - rhs: Operand::Register(1), - })); - } - _ => panic!("Invalid operator for AdditiveExpression: {:?}", self.op), - } - } - } - pub fn is_return_reference(&self, _instructions: &InstructionGenerator) -> bool { - false - } - pub fn get_typeinfo(&self, instructions: &InstructionGenerator) -> TypeInfo { - let lhs_type = self.lhs.get_typeinfo(instructions).remove_const(); - let rhs_type = self.rhs.get_typeinfo(instructions).remove_const(); - // choose bigger-precision type - match lhs_type { - TypeInfo::UInt8 | TypeInfo::Int8 => match rhs_type { - TypeInfo::UInt8 | TypeInfo::Int8 => TypeInfo::UInt8, - TypeInfo::UInt16 | TypeInfo::Int16 => TypeInfo::UInt16, - TypeInfo::UInt32 | TypeInfo::Int32 => TypeInfo::UInt32, - TypeInfo::UInt64 | TypeInfo::Int64 => TypeInfo::UInt64, - TypeInfo::Float32 => TypeInfo::Float32, - TypeInfo::Float64 => TypeInfo::Float64, - _ => panic!( - "{:?} not implemented between {:?} and {:?}", - self.op, - self.lhs.get_typeinfo(instructions), - self.rhs.get_typeinfo(instructions) - ), - }, - TypeInfo::UInt16 | TypeInfo::Int16 => match rhs_type { - TypeInfo::UInt8 | TypeInfo::Int8 => TypeInfo::UInt16, - TypeInfo::UInt16 | TypeInfo::Int16 => TypeInfo::UInt16, - TypeInfo::UInt32 | TypeInfo::Int32 => TypeInfo::UInt32, - TypeInfo::UInt64 | TypeInfo::Int64 => TypeInfo::UInt64, - TypeInfo::Float32 => TypeInfo::Float32, - TypeInfo::Float64 => TypeInfo::Float64, - _ => panic!( - "{:?} not implemented between {:?} and {:?}", - self.op, - self.lhs.get_typeinfo(instructions), - self.rhs.get_typeinfo(instructions) - ), - }, - TypeInfo::UInt32 | TypeInfo::Int32 => match rhs_type { - TypeInfo::UInt8 | TypeInfo::Int8 => TypeInfo::UInt32, - TypeInfo::UInt16 | TypeInfo::Int16 => TypeInfo::UInt32, - TypeInfo::UInt32 | TypeInfo::Int32 => TypeInfo::UInt32, - TypeInfo::UInt64 | TypeInfo::Int64 => TypeInfo::UInt64, - TypeInfo::Float32 => TypeInfo::Float32, - TypeInfo::Float64 => TypeInfo::Float64, - _ => panic!( - "{:?} not implemented between {:?} and {:?}", - self.op, - self.lhs.get_typeinfo(instructions), - self.rhs.get_typeinfo(instructions) - ), - }, - TypeInfo::UInt64 | TypeInfo::Int64 => match rhs_type { - TypeInfo::UInt8 | TypeInfo::Int8 => TypeInfo::UInt64, - TypeInfo::UInt16 | TypeInfo::Int16 => TypeInfo::UInt64, - TypeInfo::UInt32 | TypeInfo::Int32 => TypeInfo::UInt64, - TypeInfo::UInt64 | TypeInfo::Int64 => TypeInfo::UInt64, - TypeInfo::Float32 => TypeInfo::Float32, - TypeInfo::Float64 => TypeInfo::Float64, - _ => panic!( - "{:?} not implemented between {:?} and {:?}", - self.op, - self.lhs.get_typeinfo(instructions), - self.rhs.get_typeinfo(instructions) - ), - }, - TypeInfo::Float32 => match rhs_type { - TypeInfo::UInt8 | TypeInfo::Int8 => TypeInfo::Float32, - TypeInfo::UInt16 | TypeInfo::Int16 => TypeInfo::Float32, - TypeInfo::UInt32 | TypeInfo::Int32 => TypeInfo::Float32, - TypeInfo::UInt64 | TypeInfo::Int64 => TypeInfo::Float32, - TypeInfo::Float32 => TypeInfo::Float32, - TypeInfo::Float64 => TypeInfo::Float64, - _ => panic!( - "{:?} not implemented between {:?} and {:?}", - self.op, - self.lhs.get_typeinfo(instructions), - self.rhs.get_typeinfo(instructions) - ), - }, - TypeInfo::Float64 => match rhs_type { - TypeInfo::UInt8 | TypeInfo::Int8 => TypeInfo::Float64, - TypeInfo::UInt16 | TypeInfo::Int16 => TypeInfo::Float64, - TypeInfo::UInt32 | TypeInfo::Int32 => TypeInfo::Float64, - TypeInfo::UInt64 | TypeInfo::Int64 => TypeInfo::Float64, - TypeInfo::Float32 => TypeInfo::Float64, - TypeInfo::Float64 => TypeInfo::Float64, - _ => panic!( - "{:?} not implemented between {:?} and {:?}", - self.op, - self.lhs.get_typeinfo(instructions), - self.rhs.get_typeinfo(instructions) - ), - }, - TypeInfo::Pointer(t) => match rhs_type { - TypeInfo::UInt8 | TypeInfo::Int8 => TypeInfo::Pointer(t), - TypeInfo::UInt16 | TypeInfo::Int16 => TypeInfo::Pointer(t), - TypeInfo::UInt32 | TypeInfo::Int32 => TypeInfo::Pointer(t), - TypeInfo::UInt64 | TypeInfo::Int64 => TypeInfo::Pointer(t), - _ => panic!( - "{:?} not implemented between {:?} and {:?}", - self.op, - self.lhs.get_typeinfo(instructions), - self.rhs.get_typeinfo(instructions) - ), - }, - TypeInfo::Array(t, _) => match rhs_type { - TypeInfo::UInt8 | TypeInfo::Int8 => TypeInfo::Pointer(t), - TypeInfo::UInt16 | TypeInfo::Int16 => TypeInfo::Pointer(t), - TypeInfo::UInt32 | TypeInfo::Int32 => TypeInfo::Pointer(t), - TypeInfo::UInt64 | TypeInfo::Int64 => TypeInfo::Pointer(t), - _ => panic!( - "{:?} not implemented between {:?} and {:?}", - self.op, - self.lhs.get_typeinfo(instructions), - self.rhs.get_typeinfo(instructions) - ), - }, - _ => panic!( - "{:?} not implemented between {:?} and {:?}", - self.op, - self.lhs.get_typeinfo(instructions), - self.rhs.get_typeinfo(instructions) - ), - } - } -} -#[derive(Debug, Clone)] -pub struct ExprMultiplicative { - pub op: BinaryOperator, - pub lhs: Box, - pub rhs: Box, -} -impl ExprMultiplicative { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - self.rhs.emit(instructions); - if self.rhs.is_return_reference(instructions) { - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Derefed(0, 0), - })); - } else { - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Register(0), - })); - } - - self.lhs.emit(instructions); - if self.lhs.is_return_reference(instructions) { - instructions.push(Instruction::Assign(Assign { - lhs_type: self.get_typeinfo(instructions), - lhs: Operand::Register(0), - rhs: Operand::Derefed(0, 0), - })); - } else { - instructions.push(Instruction::Assign(Assign { - lhs_type: self.get_typeinfo(instructions), - lhs: Operand::Register(0), - rhs: Operand::Register(0), - })); - } - instructions.push(Instruction::PopStack(PopStack { - operand: Operand::Register(1), - })); - - match self.op { - BinaryOperator::Mul => { - instructions.push(Instruction::MulAssign(MulAssign { - lhs: Operand::Register(0), - rhs: Operand::Register(1), - })); - } - BinaryOperator::Div => { - instructions.push(Instruction::DivAssign(DivAssign { - lhs: Operand::Register(0), - rhs: Operand::Register(1), - })); - } - BinaryOperator::Mod => { - instructions.push(Instruction::ModAssign(ModAssign { - lhs: Operand::Register(0), - rhs: Operand::Register(1), - })); - } - _ => panic!( - "Invalid operator for MultiplicativeExpression: {:?}", - self.op - ), - } - } - pub fn is_return_reference(&self, _instructions: &InstructionGenerator) -> bool { - false - } - pub fn get_typeinfo(&self, instructions: &InstructionGenerator) -> TypeInfo { - let lhs_type = self.lhs.get_typeinfo(instructions).remove_const(); - let rhs_type = self.rhs.get_typeinfo(instructions).remove_const(); - // choose bigger-precision type - match lhs_type { - TypeInfo::UInt8 | TypeInfo::Int8 => match rhs_type { - TypeInfo::UInt8 | TypeInfo::Int8 => TypeInfo::UInt8, - TypeInfo::UInt16 | TypeInfo::Int16 => TypeInfo::UInt16, - TypeInfo::UInt32 | TypeInfo::Int32 => TypeInfo::UInt32, - TypeInfo::UInt64 | TypeInfo::Int64 => TypeInfo::UInt64, - TypeInfo::Float32 => TypeInfo::Float32, - TypeInfo::Float64 => TypeInfo::Float64, - _ => panic!( - "{:?} not implemented between {:?} and {:?}", - self.op, - self.lhs.get_typeinfo(instructions), - self.rhs.get_typeinfo(instructions) - ), - }, - TypeInfo::UInt16 | TypeInfo::Int16 => match rhs_type { - TypeInfo::UInt8 | TypeInfo::Int8 => TypeInfo::UInt16, - TypeInfo::UInt16 | TypeInfo::Int16 => TypeInfo::UInt16, - TypeInfo::UInt32 | TypeInfo::Int32 => TypeInfo::UInt32, - TypeInfo::UInt64 | TypeInfo::Int64 => TypeInfo::UInt64, - TypeInfo::Float32 => TypeInfo::Float32, - TypeInfo::Float64 => TypeInfo::Float64, - _ => panic!( - "{:?} not implemented between {:?} and {:?}", - self.op, - self.lhs.get_typeinfo(instructions), - self.rhs.get_typeinfo(instructions) - ), - }, - TypeInfo::UInt32 | TypeInfo::Int32 => match rhs_type { - TypeInfo::UInt8 | TypeInfo::Int8 => TypeInfo::UInt32, - TypeInfo::UInt16 | TypeInfo::Int16 => TypeInfo::UInt32, - TypeInfo::UInt32 | TypeInfo::Int32 => TypeInfo::UInt32, - TypeInfo::UInt64 | TypeInfo::Int64 => TypeInfo::UInt64, - TypeInfo::Float32 => TypeInfo::Float32, - TypeInfo::Float64 => TypeInfo::Float64, - _ => panic!( - "{:?} not implemented between {:?} and {:?}", - self.op, - self.lhs.get_typeinfo(instructions), - self.rhs.get_typeinfo(instructions) - ), - }, - TypeInfo::UInt64 | TypeInfo::Int64 => match rhs_type { - TypeInfo::UInt8 | TypeInfo::Int8 => TypeInfo::UInt64, - TypeInfo::UInt16 | TypeInfo::Int16 => TypeInfo::UInt64, - TypeInfo::UInt32 | TypeInfo::Int32 => TypeInfo::UInt64, - TypeInfo::UInt64 | TypeInfo::Int64 => TypeInfo::UInt64, - TypeInfo::Float32 => TypeInfo::Float32, - TypeInfo::Float64 => TypeInfo::Float64, - _ => panic!( - "{:?} not implemented between {:?} and {:?}", - self.op, - self.lhs.get_typeinfo(instructions), - self.rhs.get_typeinfo(instructions) - ), - }, - TypeInfo::Float32 => match rhs_type { - TypeInfo::UInt8 | TypeInfo::Int8 => TypeInfo::Float32, - TypeInfo::UInt16 | TypeInfo::Int16 => TypeInfo::Float32, - TypeInfo::UInt32 | TypeInfo::Int32 => TypeInfo::Float32, - TypeInfo::UInt64 | TypeInfo::Int64 => TypeInfo::Float32, - TypeInfo::Float32 => TypeInfo::Float32, - TypeInfo::Float64 => TypeInfo::Float64, - _ => panic!( - "{:?} not implemented between {:?} and {:?}", - self.op, - self.lhs.get_typeinfo(instructions), - self.rhs.get_typeinfo(instructions) - ), - }, - TypeInfo::Float64 => match rhs_type { - TypeInfo::UInt8 | TypeInfo::Int8 => TypeInfo::Float64, - TypeInfo::UInt16 | TypeInfo::Int16 => TypeInfo::Float64, - TypeInfo::UInt32 | TypeInfo::Int32 => TypeInfo::Float64, - TypeInfo::UInt64 | TypeInfo::Int64 => TypeInfo::Float64, - TypeInfo::Float32 => TypeInfo::Float64, - TypeInfo::Float64 => TypeInfo::Float64, - _ => panic!( - "{:?} not implemented between {:?} and {:?}", - self.op, - self.lhs.get_typeinfo(instructions), - self.rhs.get_typeinfo(instructions) - ), - }, - _ => panic!( - "{:?} not implemented between {:?} and {:?}", - self.op, - self.lhs.get_typeinfo(instructions), - self.rhs.get_typeinfo(instructions) - ), - } - } -} -#[derive(Debug, Clone)] -pub struct ExprShift { - pub op: BinaryOperator, - pub lhs: Box, - pub rhs: Box, -} -impl ExprShift { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - self.rhs.emit(instructions); - if self.rhs.is_return_reference(instructions) { - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Derefed(0, 0), - })); - } else { - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Register(0), - })); - } - - self.lhs.emit(instructions); - if self.lhs.is_return_reference(instructions) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(0, 0), - operand_to: Operand::Register(0), - })); - } - - instructions.push(Instruction::PopStack(PopStack { - operand: Operand::Register(1), - })); - - match self.op { - BinaryOperator::ShiftLeft => { - instructions.push(Instruction::ShiftLeftAssign(ShiftLeftAssign { - lhs: Operand::Register(0), - rhs: Operand::Register(1), - })); - } - BinaryOperator::ShiftRight => { - instructions.push(Instruction::ShiftRightAssign(ShiftRightAssign { - lhs: Operand::Register(0), - rhs: Operand::Register(1), - })); - } - _ => panic!("Invalid operator for ShiftExpression: {:?}", self.op), - } - } - pub fn is_return_reference(&self, _instructions: &InstructionGenerator) -> bool { - false - } - pub fn get_typeinfo(&self, instructions: &InstructionGenerator) -> TypeInfo { - self.lhs.get_typeinfo(instructions) - } -} -#[derive(Debug, Clone)] -pub struct ExprBitwise { - pub op: BinaryOperator, - pub lhs: Box, - pub rhs: Box, -} -impl ExprBitwise { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - self.rhs.emit(instructions); - if self.rhs.is_return_reference(instructions) { - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Derefed(0, 0), - })); - } else { - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Register(0), - })); - } - - self.lhs.emit(instructions); - if self.lhs.is_return_reference(instructions) { - instructions.push(Instruction::Assign(Assign { - lhs_type: self.get_typeinfo(instructions), - lhs: Operand::Register(0), - rhs: Operand::Derefed(0, 0), - })); - } else { - instructions.push(Instruction::Assign(Assign { - lhs_type: self.get_typeinfo(instructions), - lhs: Operand::Register(0), - rhs: Operand::Register(0), - })); - } - instructions.push(Instruction::PopStack(PopStack { - operand: Operand::Register(1), - })); - - match self.op { - BinaryOperator::BitwiseAnd => { - instructions.push(Instruction::BitwiseAndAssign(BitwiseAndAssign { - lhs: Operand::Register(0), - rhs: Operand::Register(1), - })); - } - BinaryOperator::BitwiseOr => { - instructions.push(Instruction::BitwiseOrAssign(BitwiseOrAssign { - lhs: Operand::Register(0), - rhs: Operand::Register(1), - })); - } - BinaryOperator::BitwiseXor => { - instructions.push(Instruction::BitwiseXorAssign(BitwiseXorAssign { - lhs: Operand::Register(0), - rhs: Operand::Register(1), - })); - } - _ => panic!("Invalid operator for BitwiseExpression: {:?}", self.op), - } - } - pub fn is_return_reference(&self, _instructions: &InstructionGenerator) -> bool { - false - } - pub fn get_typeinfo(&self, instructions: &InstructionGenerator) -> TypeInfo { - let lhs_type = self.lhs.get_typeinfo(instructions).remove_const(); - let rhs_type = self.rhs.get_typeinfo(instructions).remove_const(); - // choose bigger-precision type - match lhs_type { - TypeInfo::UInt8 | TypeInfo::Int8 => match rhs_type { - TypeInfo::UInt8 | TypeInfo::Int8 => TypeInfo::UInt8, - TypeInfo::UInt16 | TypeInfo::Int16 => TypeInfo::UInt16, - TypeInfo::UInt32 | TypeInfo::Int32 => TypeInfo::UInt32, - TypeInfo::UInt64 | TypeInfo::Int64 => TypeInfo::UInt64, - _ => panic!( - "{:?} not implemented between {:?} and {:?}", - self.op, - self.lhs.get_typeinfo(instructions), - self.rhs.get_typeinfo(instructions) - ), - }, - TypeInfo::UInt16 | TypeInfo::Int16 => match rhs_type { - TypeInfo::UInt8 | TypeInfo::Int8 => TypeInfo::UInt16, - TypeInfo::UInt16 | TypeInfo::Int16 => TypeInfo::UInt16, - TypeInfo::UInt32 | TypeInfo::Int32 => TypeInfo::UInt32, - TypeInfo::UInt64 | TypeInfo::Int64 => TypeInfo::UInt64, - _ => panic!( - "{:?} not implemented between {:?} and {:?}", - self.op, - self.lhs.get_typeinfo(instructions), - self.rhs.get_typeinfo(instructions) - ), - }, - TypeInfo::UInt32 | TypeInfo::Int32 => match rhs_type { - TypeInfo::UInt8 | TypeInfo::Int8 => TypeInfo::UInt32, - TypeInfo::UInt16 | TypeInfo::Int16 => TypeInfo::UInt32, - TypeInfo::UInt32 | TypeInfo::Int32 => TypeInfo::UInt32, - TypeInfo::UInt64 | TypeInfo::Int64 => TypeInfo::UInt64, - _ => panic!( - "{:?} not implemented between {:?} and {:?}", - self.op, - self.lhs.get_typeinfo(instructions), - self.rhs.get_typeinfo(instructions) - ), - }, - TypeInfo::UInt64 | TypeInfo::Int64 => match rhs_type { - TypeInfo::UInt8 | TypeInfo::Int8 => TypeInfo::UInt64, - TypeInfo::UInt16 | TypeInfo::Int16 => TypeInfo::UInt64, - TypeInfo::UInt32 | TypeInfo::Int32 => TypeInfo::UInt64, - TypeInfo::UInt64 | TypeInfo::Int64 => TypeInfo::UInt64, - _ => panic!( - "{:?} not implemented between {:?} and {:?}", - self.op, - self.lhs.get_typeinfo(instructions), - self.rhs.get_typeinfo(instructions) - ), - }, - _ => panic!( - "{:?} not implemented between {:?} and {:?}", - self.op, - self.lhs.get_typeinfo(instructions), - self.rhs.get_typeinfo(instructions) - ), - } - } -} - -#[derive(Debug, Clone)] -pub struct ExprPostArrow { - pub src: Box, - pub member: String, -} -impl ExprPostArrow { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - let member_offset = match self.src.get_typeinfo(instructions).remove_const() { - TypeInfo::Pointer(t) => match instructions.get_true_typeinfo(t.as_ref()).remove_const() - { - TypeInfo::Struct(sinfo) => { - let mut member_offset: Option = None; - for (_, name, offset) in sinfo.fields.as_ref().unwrap() { - if name == &self.member { - member_offset = Some(*offset); - break; - } - } - member_offset.expect(format!("member not found: {:?}", self.member).as_str()) - } - _ => panic!("-> operator on non-struct type: {:?}", t), - }, - _ => panic!( - "-> operator on non-pointer type: {:?}", - self.src.get_typeinfo(instructions) - ), - }; - - self.src.emit(instructions); - if self.src.is_return_reference(instructions) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(0, 0), - operand_to: Operand::Register(0), - })); - } - instructions.push(Instruction::AddAssign(AddAssign { - lhs: Operand::Register(0), - rhs: Operand::Value(VariableData::UInt64(member_offset as u64)), - })); - } - pub fn get_typeinfo(&self, instructions: &InstructionGenerator) -> TypeInfo { - match self.src.get_typeinfo(instructions).remove_const() { - TypeInfo::Pointer(t) => { - let t_type = instructions.get_true_typeinfo(t.as_ref()); - match t_type.remove_const() { - TypeInfo::Struct(sinfo) => { - let mut member_type: Option = None; - for (type_, name, _) in sinfo.fields.as_ref().unwrap() { - if name == &self.member { - member_type = Some(type_.clone()); - break; - } - } - let member_type = member_type - .expect(format!("member not found: {:?}", self.member).as_str()); - if t_type.is_const() { - member_type.add_const() - } else { - member_type - } - } - _ => panic!("-> operator on non-struct type: {:?}", t), - } - } - _ => panic!( - "-> operator on non-pointer type: {:?}", - self.src.get_typeinfo(instructions) - ), - } - } - pub fn is_return_reference(&self, instructions: &InstructionGenerator) -> bool { - match self.get_typeinfo(instructions).remove_const() { - TypeInfo::Array(_, _) => false, - _ => true, - } - } -} - -#[derive(Debug, Clone)] -pub struct ExprConditional { - pub cond: Box, - pub then_expr: Box, - pub else_expr: Box, -} -impl ExprConditional { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - let else_label = instructions.get_unique_label(); - let end_label = instructions.get_unique_label(); - - self.cond.emit(instructions); - if self.cond.is_return_reference(instructions) { - instructions.push(Instruction::JumpZero(JumpZero { - label: else_label.clone(), - operand_cond: Operand::Derefed(0, 0), - })); - } else { - instructions.push(Instruction::JumpZero(JumpZero { - label: else_label.clone(), - operand_cond: Operand::Register(0), - })); - } - - self.then_expr.emit(instructions); - if self.then_expr.is_return_reference(instructions) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(0, 0), - operand_to: Operand::Register(1), - })); - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Register(1), - operand_to: Operand::Register(0), - })); - } - instructions.push(Instruction::Jump(Jump { - label: end_label.clone(), - })); - instructions.set_label(&else_label); - self.else_expr.emit(instructions); - if self.else_expr.is_return_reference(instructions) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(0, 0), - operand_to: Operand::Register(1), - })); - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Register(1), - operand_to: Operand::Register(0), - })); - } - instructions.set_label(&end_label); - } - pub fn get_typeinfo(&self, instructions: &InstructionGenerator) -> TypeInfo { - self.then_expr.get_typeinfo(instructions) - } - pub fn is_return_reference(&self, _instructions: &InstructionGenerator) -> bool { - false - } -} - -#[derive(Debug, Clone)] -pub struct ExprComma { - pub lhs: Box, - pub rhs: Box, -} -impl ExprComma { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - self.lhs.emit(instructions); - self.rhs.emit(instructions); - } - pub fn is_return_reference(&self, instructions: &InstructionGenerator) -> bool { - self.rhs.is_return_reference(instructions) - } - pub fn get_typeinfo(&self, instructions: &InstructionGenerator) -> TypeInfo { - self.rhs.get_typeinfo(instructions) - } -} #[derive(Debug, Clone)] pub struct ExprInitializerList { pub initializers: Vec, } -impl ExprInitializerList { - pub fn emit(&self, _instructions: &mut InstructionGenerator) { - panic!("InitializerListExpression.eval not implemented"); - } - pub fn get_typeinfo(&self, _instructions: &InstructionGenerator) -> TypeInfo { - panic!("InitializerListExpression.get_typeinfo not implemented"); - } - pub fn is_return_reference(&self, _instructions: &InstructionGenerator) -> bool { - panic!("InitializerListExpression.is_return_reference not implemented"); - } -} diff --git a/src/ast/mod.rs b/src/ast/mod.rs index bd32764..50b622d 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -1,5 +1,41 @@ -pub mod declarator; -pub mod expression; -pub mod parser; -pub mod statement; -pub mod typename; +mod declarator; +mod expression; +mod parser_lr; +mod statement; + +pub use declarator::DeclarationSpecifier; +pub use declarator::Declarator; +pub use declarator::EnumSpecifier; +pub use declarator::Enumerator; +pub use declarator::ParameterDeclaration; +pub use declarator::ParameterList; +pub use declarator::SpecifierQualifier; +pub use declarator::StorageClassSpecifier; +pub use declarator::StructDeclaration; +pub use declarator::StructOrUnionSpecifier; +pub use declarator::TypeQualifier; +pub use declarator::TypeSpecifier; +pub use declarator::Typename; +pub use expression::ExprArrow; +pub use expression::ExprBracket; +pub use expression::ExprCast; +pub use expression::ExprConditional; +pub use expression::ExprConstantDouble; +pub use expression::ExprMember; +pub use expression::ExprParen; +pub use expression::ExprSizeOfExpr; +pub use expression::ExprSizeOfType; +pub use expression::ExprString; +pub use expression::ExprUnary; +pub use expression::Expression; +pub use statement::Statement; +pub use statement::StmtBreak; +pub use statement::StmtContinue; +pub use statement::StmtDoWhile; +pub use statement::StmtFor; +pub use statement::StmtGoto; +pub use statement::StmtIf; +pub use statement::StmtLabeled; +pub use statement::StmtReturn; +pub use statement::StmtSwitch; +pub use statement::StmtWhile; diff --git a/src/ast/parser.rs b/src/ast/parser.rs deleted file mode 100644 index 8899286..0000000 --- a/src/ast/parser.rs +++ /dev/null @@ -1,2214 +0,0 @@ -use std::cell::RefCell; -use std::collections::HashMap; -use std::rc::Rc; - -use super::declarator::*; -use super::expression::*; -use super::statement::*; -use super::typename::*; - -use crate::token::Token; - -use rusty_parser::{self as rp, IntoParser}; - -pub struct ASTParser { - type_name: Rc>>, // ? Only Single typename, no pointer - type_specifier: Rc>>, // OK - parameter_list: Rc, TypeInfo)>,), Token>>>, // OK - declarator: Rc>>, // OK - init_declarator: Rc>>, // OK - abstract_declarator: Rc>>, // OK - pointer: Rc,), Token>>>, - - expression: Rc>>, //OK - assignment_expression: Rc>>, // OK - constant_expression: Rc>>, // OK - initializer: Rc>>, // OK - - statement: Rc>>, // OK - compound_statement: Rc>>, // OK - declaration: Rc>>, // OK - - translation_unit: Rc>>, // OK -} - -impl ASTParser { - pub fn new() -> Self { - let mut s = Self { - type_name: Default::default(), - type_specifier: Default::default(), - - expression: Default::default(), - constant_expression: Default::default(), - assignment_expression: Default::default(), - initializer: Default::default(), - - statement: Default::default(), - compound_statement: Default::default(), - declaration: Default::default(), - parameter_list: Default::default(), - - declarator: Default::default(), - init_declarator: Default::default(), - abstract_declarator: Default::default(), - pointer: Default::default(), - - translation_unit: Default::default(), - }; - - s.expression_parser(); - s.statement_parser(); - s.declarator(); - s.type_name(); - s.translation_unit_parser(); - - s - } - - pub fn parse(&self, input: Vec) -> TranslationUnit { - let res = rp::parse(&self.translation_unit, input.iter().cloned()); - if let Some((out,)) = res.output { - return out; - } - panic!("Failed to parse AST"); - } - fn type_name(&mut self) { - /* - unsigned (char | short | int | long long | long | ) - signed (char | short | int | long long | ) - char - short - int - long long - long - float - double - */ - let unsigned_specifier = rp::seq!( - rp::one(Token::Unsigned).void(), - rp::or!( - rp::one(Token::Char).void().map(|| TypeInfo::UInt8), - rp::one(Token::Short).void().map(|| TypeInfo::UInt16), - rp::one(Token::Int).void().map(|| TypeInfo::UInt32), - rp::seq!(rp::one(Token::Long), rp::one(Token::Long)) - .void() - .map(|| TypeInfo::UInt64), - rp::one(Token::Long).void().map(|| TypeInfo::UInt64) - ) - .optional_or(TypeInfo::UInt32) - ); - let signed_specifier = rp::seq!( - rp::one(Token::Unsigned).void(), - rp::or!( - rp::one(Token::Char).void().map(|| TypeInfo::Int8), - rp::one(Token::Short).void().map(|| TypeInfo::Int16), - rp::one(Token::Int).void().map(|| TypeInfo::Int32), - rp::seq!(rp::one(Token::Long), rp::one(Token::Long)) - .void() - .map(|| TypeInfo::Int64), - rp::one(Token::Long).void().map(|| TypeInfo::Int64) - ) - .optional_or(TypeInfo::Int32) - ); - let floating_specifier = rp::or!( - rp::one(Token::Float).void().map(|| TypeInfo::Float32), - rp::one(Token::Double).void().map(|| TypeInfo::Float64) - ); - let primitive_specifier = rp::or!( - rp::one(Token::Void).void().map(|| TypeInfo::Void), - rp::one(Token::Char).void().map(|| TypeInfo::Int8), - rp::one(Token::Short).void().map(|| TypeInfo::Int16), - rp::one(Token::Int).void().map(|| TypeInfo::Int32), - rp::seq!(rp::one(Token::Long), rp::one(Token::Long)) - .void() - .map(|| TypeInfo::Int64), - rp::one(Token::Long).void().map(|| TypeInfo::Int64), - unsigned_specifier, - signed_specifier, - floating_specifier - ); - let struct_specifier: Rc>> = - Default::default(); - let union_specifier: Rc>> = Default::default(); - let enum_specifier: Rc>> = Default::default(); - - /* - type_specifier - : VOID - | CHAR - | SHORT - | INT - | LONG - | FLOAT - | DOUBLE - | SIGNED - | UNSIGNED - | struct_or_union_specifier - | enum_specifier - | TYPE_NAME - ; - */ - let type_specifier = rp::or!( - primitive_specifier, - struct_specifier.clone().map(|s| TypeInfo::Struct(s)), - union_specifier.clone().map(|s| TypeInfo::Union(s)), - enum_specifier.clone().map(|e| TypeInfo::Enum(e)), - rp::check(|t: Token| -> Option { - if let Token::Identifier(s) = t { - Some(TypeInfo::Identifier(s)) - } else { - None - } - }) - ); - - let consts = rp::one(Token::Const).repeat(0..); - - let type_specifier = rp::seq!(consts.clone(), type_specifier, consts).map( - |consts: Vec, specifier: TypeInfo, consts2: Vec| -> TypeInfo { - if consts.is_empty() == false || consts2.is_empty() == false { - TypeInfo::Const(Box::new(specifier)) - } else { - specifier - } - }, - ); - - self.type_specifier.borrow_mut().assign(type_specifier); - - let type_name = rp::seq!( - self.type_specifier.clone(), - self.abstract_declarator.clone().optional() - ) - .map( - |specifier: TypeInfo, declarator: Option| -> TypeInfo { - if let Some(declarator) = declarator { - declarator.resolve_typeinfo(specifier).1 - } else { - specifier - } - }, - ); - self.type_name.borrow_mut().assign(type_name); - - /* - struct_member_declaration - : type_specifier declarator+',' ';' - ; - */ - let declarators = self - .declarator - .clone() - .map(|d: Declarator| -> Vec { vec![d] }) - .reduce_left( - rp::seq!(rp::one(Token::Comma).void(), self.declarator.clone()), - |mut v: Vec, d: Declarator| -> Vec { - v.push(d); - v - }, - ); - - let struct_member_declaration = rp::seq!( - self.type_specifier.clone(), - declarators, - rp::one(Token::SemiColon).void() - ) - .map( - |specifier: TypeInfo, declarators: Vec| -> Vec<(String, TypeInfo)> { - let mut ret = Vec::new(); - for declarator in declarators.into_iter() { - let var = declarator.resolve_typeinfo(specifier.clone()); - ret.push((var.0.expect("Variable name is required"), var.1)); - } - ret - }, - ); - - /* - struct_or_union_specifier - : struct_or_union IDENTIFIER '{' struct_member_declaration* '}' - | struct_or_union '{' struct_member_declaration* '}' - | struct_or_union IDENTIFIER - ; - */ - let struct_specifier1 = rp::seq!( - rp::one(Token::Struct).void(), - rp::check(|t: Token| -> Option { - if let Token::Identifier(s) = t { - Some(s) - } else { - None - } - }), - rp::one(Token::LeftBrace).void(), - struct_member_declaration.clone().repeat(0..), - rp::one(Token::RightBrace).void() - ) - .map( - |name: String, memberss: Vec>| -> StructInfo { - let mut fields: Vec<(TypeInfo, String, usize)> = Vec::new(); - let mut offset: usize = 0; - for members in memberss.into_iter() { - for member in members.into_iter() { - fields.push((member.1.clone(), member.0.clone(), offset)); - offset += member.1.number_of_primitives(); - - // TODO duplicate check - } - } - StructInfo { - name: Some(name), - fields: Some(fields), - } - }, - ); - let struct_specifier2 = rp::seq!( - rp::one(Token::Struct).void(), - rp::one(Token::LeftBrace).void(), - struct_member_declaration.clone().repeat(0..), - rp::one(Token::RightBrace).void() - ) - .map(|memberss: Vec>| -> StructInfo { - let mut fields: Vec<(TypeInfo, String, usize)> = Vec::new(); - let mut offset: usize = 0; - for members in memberss.into_iter() { - for member in members.into_iter() { - fields.push((member.1.clone(), member.0.clone(), offset)); - offset += member.1.number_of_primitives(); - - // TODO duplicate check - } - } - StructInfo { - name: None, - fields: Some(fields), - } - }); - let struct_specifier3 = rp::seq!( - rp::one(Token::Struct).void(), - rp::check(|t: Token| -> Option { - if let Token::Identifier(s) = t { - Some(s) - } else { - None - } - }) - ) - .map(|name: String| -> StructInfo { - StructInfo { - name: Some(name), - fields: None, - } - }); - - struct_specifier.borrow_mut().assign(rp::or!( - struct_specifier1, - struct_specifier2, - struct_specifier3 - )); - - /* - struct_or_union_specifier - : struct_or_union IDENTIFIER '{' struct_member_declaration* '}' - | struct_or_union '{' struct_member_declaration* '}' - | struct_or_union IDENTIFIER - ; - */ - let union_specifier1 = rp::seq!( - rp::one(Token::Union).void(), - rp::check(|t: Token| -> Option { - if let Token::Identifier(s) = t { - Some(s) - } else { - None - } - }), - rp::one(Token::LeftBrace).void(), - struct_member_declaration.clone().repeat(0..), - rp::one(Token::RightBrace).void() - ) - .map( - |name: String, memberss: Vec>| -> UnionInfo { - let mut fields: HashMap = HashMap::new(); - for members in memberss.into_iter() { - for member in members.into_iter() { - let old = fields.insert(member.0.clone(), member.1); - if old.is_some() { - panic!("Duplicated field name: {}", member.0); - } - } - } - UnionInfo { - name: Some(name), - fields: Some(fields), - } - }, - ); - let union_specifier2 = rp::seq!( - rp::one(Token::Union).void(), - rp::one(Token::LeftBrace).void(), - struct_member_declaration.clone().repeat(0..), - rp::one(Token::RightBrace).void() - ) - .map(|memberss: Vec>| -> UnionInfo { - let mut fields: HashMap = HashMap::new(); - for members in memberss.into_iter() { - for member in members.into_iter() { - let old = fields.insert(member.0.clone(), member.1); - if old.is_some() { - panic!("Duplicated field name: {}", member.0); - } - } - } - UnionInfo { - name: None, - fields: Some(fields), - } - }); - let union_specifier3 = rp::seq!( - rp::one(Token::Union).void(), - rp::check(|t: Token| -> Option { - if let Token::Identifier(s) = t { - Some(s) - } else { - None - } - }) - ) - .map(|name: String| -> UnionInfo { - UnionInfo { - name: Some(name), - fields: None, - } - }); - - union_specifier.borrow_mut().assign(rp::or!( - union_specifier1, - union_specifier2, - union_specifier3 - )); - - /* - enumerator - : IDENTIFIER - | IDENTIFIER '=' constant_expression - ; - */ - struct Enumerator { - pub name: String, - pub value: Option, - } - let enumerator = rp::seq!( - rp::check(|t: Token| -> Option { - if let Token::Identifier(s) = t { - Some(s) - } else { - None - } - }), - rp::seq!( - rp::one(Token::Equal).void(), - self.constant_expression.clone() - ) - .optional() - ) - .map(|name: String, value: Option| Enumerator { name, value }); - - /* - enumerator_list - : enumerator - | enumerator_list ',' enumerator - ; - */ - let enumerator_list = enumerator - .clone() - .map(|e| -> Vec { vec![e] }) - .reduce_left( - rp::seq!(rp::one(Token::Comma).void(), enumerator.clone()), - |mut v: Vec, e: Enumerator| -> Vec { - v.push(e); - v - }, - ); - /* - enum_specifier - : ENUM '{' enumerator_list '}' - | ENUM IDENTIFIER '{' enumerator_list '}' - | ENUM IDENTIFIER - ; - */ - let enum_specifier1 = rp::seq!( - rp::one(Token::Enum).void(), - rp::one(Token::LeftBrace).void(), - enumerator_list.clone(), - rp::one(Token::RightBrace).void() - ) - .map(|enumerators: Vec| -> EnumInfo { - let mut fields: HashMap = HashMap::new(); - let mut last_enum_value: Option = None; - for enumerator in enumerators.into_iter() { - let enum_value: i64 = if let Some(value) = enumerator.value { - value - .get_constant_i64() - .expect("Enumerator value must be constant expression") - } else { - if last_enum_value.is_none() { - 0 - } else { - last_enum_value.unwrap() + 1 - } - }; - let old = fields.insert(enumerator.name.clone(), enum_value); - if old.is_some() { - panic!("Duplicated enumerator name: {}", enumerator.name); - } - last_enum_value = Some(enum_value); - } - EnumInfo { - name: None, - fields: Some(fields), - } - }); - - let enum_specifier2 = rp::seq!( - rp::one(Token::Enum).void(), - rp::check(|t: Token| -> Option { - if let Token::Identifier(s) = t { - Some(s) - } else { - None - } - }), - rp::one(Token::LeftBrace).void(), - enumerator_list.clone(), - rp::one(Token::RightBrace).void() - ) - .map(|name: String, enumerators: Vec| -> EnumInfo { - let mut fields: HashMap = HashMap::new(); - let mut last_enum_value: Option = None; - for enumerator in enumerators.into_iter() { - let enum_value: i64 = if let Some(value) = enumerator.value { - value - .get_constant_i64() - .expect("Enumerator value must be constant expression") - } else { - if last_enum_value.is_none() { - 0 - } else { - last_enum_value.unwrap() + 1 - } - }; - let old = fields.insert(enumerator.name.clone(), enum_value); - if old.is_some() { - panic!("Duplicated enumerator name: {}", enumerator.name); - } - last_enum_value = Some(enum_value); - } - EnumInfo { - name: Some(name), - fields: Some(fields), - } - }); - let enum_specifier3 = rp::seq!( - rp::one(Token::Enum).void(), - rp::check(|t: Token| -> Option { - if let Token::Identifier(s) = t { - Some(s) - } else { - None - } - }) - ) - .map(|name: String| -> EnumInfo { - EnumInfo { - name: Some(name), - fields: None, - } - }); - - enum_specifier.borrow_mut().assign(rp::or!( - enum_specifier1, - enum_specifier2, - enum_specifier3 - )); - } - fn expression_parser(&mut self) { - let primary_expression: Rc>> = - Default::default(); - let postfix_expression: Rc>> = - Default::default(); - let unary_expression: Rc>> = - Default::default(); - let cast_expression: Rc>> = - Default::default(); - let multiplicative_expression: Rc>> = - Default::default(); - let additive_expression: Rc>> = - Default::default(); - let shift_expression: Rc>> = - Default::default(); - let relational_expression: Rc>> = - Default::default(); - let equality_expression: Rc>> = - Default::default(); - let and_expression: Rc>> = Default::default(); - let exclusive_or_expression: Rc>> = - Default::default(); - let inclusive_or_expression: Rc>> = - Default::default(); - let logical_and_expression: Rc>> = - Default::default(); - let logical_or_expression: Rc>> = - Default::default(); - let conditional_expression: Rc>> = - Default::default(); - - // ======================= - // Primary expression - // ======================= - { - let identifier = rp::check(|t: Token| -> Option { - if let Token::Identifier(s) = t { - Some(Expression::PrimaryIdentifier(ExprPrimaryIdentifier { - name: s, - })) - } else { - None - } - }); - let integer_constant = rp::check(|t: Token| -> Option { - match t { - Token::ConstantUnsignedInteger(i) => Some(Expression::ConstantUnsignedInteger( - ExprConstantUnsignedInteger { value: i }, - )), - Token::ConstantInteger(i) => { - Some(Expression::ConstantInteger(ExprConstantInteger { - value: i, - })) - } - Token::ConstantCharacter(ch) => { - Some(Expression::ConstantCharacter(ExprConstantCharacter { - value: ch, - })) - } - Token::ConstantLong(l) => { - Some(Expression::ConstantLong(ExprConstantLong { value: l })) - } - Token::ConstantUnsignedLong(l) => { - Some(Expression::ConstantUnsignedLong(ExprConstantUnsignedLong { - value: l, - })) - } - _ => None, - } - }); - let float_constant = rp::check(|t: Token| -> Option { - match t { - Token::ConstantFloat(f) => { - Some(Expression::ConstantFloat(ExprConstantFloat { value: f })) - } - Token::ConstantDouble(d) => { - Some(Expression::ConstantDouble(ExprConstantDouble { value: d })) - } - _ => None, - } - }); - let string_literal = rp::check(|t: Token| -> Option { - match t { - Token::StringLiteral(s) => { - Some(Expression::StringLiteral(ExprString { value: s })) - } - _ => None, - } - }); - - /* - primary_expression - : IDENTIFIER - | CONSTANT - | STRING_LITERAL - | '(' expression ')' - ; - */ - primary_expression.borrow_mut().assign(rp::or!( - identifier, - integer_constant, - float_constant, - string_literal, - rp::seq!( - rp::one(Token::LeftParen).void(), - self.expression.clone(), - rp::one(Token::RightParen).void() - ) - )); - } - - // ======================= - // Postfix expression - // ======================= - { - enum PostfixType { - Bracket(Expression), - Paren(Vec), - Dot(String), - Arrow(String), - Inc, - Dec, - } - - let bracket = rp::seq!( - rp::one(Token::LeftBracket).void(), - self.expression.clone(), - rp::one(Token::RightBracket).void().or_else(|| -> () { - panic!("Expected ']' after index expression"); - }) - ) - .map(|e: Expression| PostfixType::Bracket(e)); - - let argument_list1 = self - .assignment_expression - .clone() - .map(|e| -> Vec { - let mut ret = Vec::new(); - ret.push(e); - ret - }) - .reduce_left( - rp::seq!( - rp::one(Token::Comma).void(), - self.assignment_expression.clone() - ), - |mut v: Vec, e: Expression| -> Vec { - v.push(e); - v - }, - ); - let argument_list0 = - argument_list1 - .optional() - .map(|args: Option>| -> Vec { - if let Some(args) = args { - args - } else { - Vec::new() - } - }); - - let paren = rp::seq!( - rp::one(Token::LeftParen).void(), - argument_list0, - rp::one(Token::RightParen).void().or_else(|| -> () { - panic!("Expected ')' for function call"); - }) - ) - .map(|args| PostfixType::Paren(args)); - - let dot = rp::seq!( - rp::one(Token::Dot).void(), - rp::check(|t: Token| -> Option { - if let Token::Identifier(s) = t { - Some(s) - } else { - panic!("Expected identifier after '.'"); - } - }) - ) - .map(|s: String| PostfixType::Dot(s)); - - let ptr_op = rp::seq!( - rp::one(Token::PtrOp).void(), - rp::check(|t: Token| -> Option { - if let Token::Identifier(s) = t { - Some(s) - } else { - panic!("Expected identifier after '->'"); - } - }) - ) - .map(|s: String| PostfixType::Arrow(s)); - - let inc_op = rp::check(|t: Token| -> Option { - if let Token::IncOp = t { - Some(PostfixType::Inc) - } else { - None - } - }); - let dec_op = rp::check(|t: Token| -> Option { - if let Token::DecOp = t { - Some(PostfixType::Dec) - } else { - None - } - }); - - /* - postfix_expression - : primary_expression - | postfix_expression '[' expression ']' - | postfix_expression '(' ')' - | postfix_expression '(' argument_expression_list ')' - | postfix_expression '.' IDENTIFIER - | postfix_expression PTR_OP IDENTIFIER - | postfix_expression INC_OP - | postfix_expression DEC_OP - ; - */ - postfix_expression - .borrow_mut() - .assign(primary_expression.clone().reduce_left( - rp::or!(bracket, paren, dot, ptr_op, inc_op, dec_op), - |lhs: Expression, rhs: PostfixType| -> Expression { - match rhs { - PostfixType::Bracket(e) => Expression::PostBracket(ExprPostBracket { - src: Box::new(lhs), - index: Box::new(e), - }), - PostfixType::Paren(args) => Expression::PostParen(ExprPostParen { - src: Box::new(lhs), - args, - }), - PostfixType::Dot(s) => Expression::PostMember(ExprPostMember { - src: Box::new(lhs), - member: s, - }), - PostfixType::Arrow(s) => Expression::PostArrow(ExprPostArrow { - src: Box::new(lhs), - member: s, - }), - PostfixType::Inc => { - Expression::PostIncrement(ExprPostIncrement { src: Box::new(lhs) }) - } - PostfixType::Dec => { - Expression::PostDecrement(ExprPostDecrement { src: Box::new(lhs) }) - } - } - }, - )); - } - - // ======================= - // Unary expression - // ======================= - { - /* - unary_operator - : '&' - | '*' - | '+' - | '-' - | '~' - | '!' - ; - */ - let unary_operator = rp::or!( - rp::one(Token::Ampersand).output(UnaryOperator::AddressOf), - rp::one(Token::Star).output(UnaryOperator::Dereference), - rp::one(Token::Plus).output(UnaryOperator::Plus), - rp::one(Token::Minus).output(UnaryOperator::Minus), - rp::one(Token::Tilde).output(UnaryOperator::BitwiseNot), - rp::one(Token::Exclamation).output(UnaryOperator::LogicalNot) - ); - - let sizeof_type = rp::seq!( - rp::one(Token::Sizeof).void(), - rp::one(Token::LeftParen).void().or_else(|| -> () { - panic!("Expected '(' after sizeof"); - }), - self.type_name.clone().or_else(|| -> TypeInfo { - panic!("Expected type name after sizeof("); - }), - rp::one(Token::RightParen).void().or_else(|| -> () { - panic!("Expected ')' after sizeof(type)"); - }) - ) - .map(|typeinfo: TypeInfo| -> Expression { - Expression::SizeofType(ExprSizeOfType { typeinfo }) - }); - - let sizeof_expr = rp::seq!(rp::one(Token::Sizeof).void(), unary_expression.clone()) - .map(|expr: Expression| -> Expression { - Expression::SizeofExpr(ExprSizeOfExpr { - expr: Box::new(expr), - }) - }); - - /* - unary_expression - : postfix_expression - | INC_OP unary_expression - | DEC_OP unary_expression - | unary_operator cast_expression - | SIZEOF unary_expression - | SIZEOF '(' type_specifier ')' - ; - */ - let unary_expression1 = rp::or!( - sizeof_expr, - sizeof_type, - rp::seq!(unary_operator, cast_expression.clone()).map( - |op: UnaryOperator, expr: Expression| -> Expression { - Expression::Unary(ExprUnary { - op, - src: Box::new(expr), - }) - } - ), - rp::seq!(rp::one(Token::IncOp).void(), unary_expression.clone()).map( - |expr: Expression| -> Expression { - Expression::Unary(ExprUnary { - op: UnaryOperator::Increment, - src: Box::new(expr), - }) - } - ), - rp::seq!(rp::one(Token::DecOp).void(), unary_expression.clone()).map( - |expr: Expression| -> Expression { - Expression::Unary(ExprUnary { - op: UnaryOperator::Decrement, - src: Box::new(expr), - }) - } - ), - postfix_expression.clone() - ); - - unary_expression.borrow_mut().assign(unary_expression1); - } - - { - /* - cast_expression - : unary_expression - | '(' type_name')' cast_expression - ; - */ - cast_expression - .borrow_mut() - .assign(unary_expression.clone().reduce_right( - rp::seq!( - rp::one(Token::LeftParen).void(), - self.type_name.clone(), - rp::one(Token::RightParen).void() - ), - |typeinfo: TypeInfo, cast_expression: Expression| -> Expression { - Expression::Cast(ExprCast { - src: Box::new(cast_expression), - typeinfo, - }) - }, - )); - } - - { - /* - multiplicative_expression - : cast_expression - | multiplicative_expression '*' cast_expression - | multiplicative_expression '/' cast_expression - | multiplicative_expression '%' cast_expression - ; - */ - let op = rp::or!( - rp::one(Token::Star).output(BinaryOperator::Mul), - rp::one(Token::Slash).output(BinaryOperator::Div), - rp::one(Token::Percent).output(BinaryOperator::Mod) - ); - - let multiplicative_ = cast_expression.clone().reduce_left( - rp::seq!(op, cast_expression.clone()), - |lhs: Expression, op: BinaryOperator, rhs: Expression| -> Expression { - Expression::Multiplicative(ExprMultiplicative { - op, - lhs: Box::new(lhs), - rhs: Box::new(rhs), - }) - }, - ); - multiplicative_expression - .borrow_mut() - .assign(multiplicative_); - } - { - /* - additive_expression - : multiplicative_expression - | additive_expression '+' multiplicative_expression - | additive_expression '-' multiplicative_expression - ; - */ - let op = rp::or!( - rp::one(Token::Plus).output(BinaryOperator::Add), - rp::one(Token::Minus).output(BinaryOperator::Sub) - ); - let additive = multiplicative_expression.clone().reduce_left( - rp::seq!(op, multiplicative_expression.clone()), - |lhs: Expression, op: BinaryOperator, rhs: Expression| -> Expression { - Expression::Additive(ExprAdditive { - op, - lhs: Box::new(lhs), - rhs: Box::new(rhs), - }) - }, - ); - additive_expression.borrow_mut().assign(additive); - } - { - /* - shift_expression - : additive_expression - | shift_expression LEFT_OP additive_expression - | shift_expression RIGHT_OP additive_expression - ; - */ - let op = rp::or!( - rp::one(Token::LeftOp).output(BinaryOperator::ShiftLeft), - rp::one(Token::RightOp).output(BinaryOperator::ShiftRight) - ); - let shift = additive_expression.clone().reduce_left( - rp::seq!(op, additive_expression.clone()), - |lhs: Expression, op: BinaryOperator, rhs: Expression| -> Expression { - Expression::Shift(ExprShift { - op, - lhs: Box::new(lhs), - rhs: Box::new(rhs), - }) - }, - ); - shift_expression.borrow_mut().assign(shift); - } - { - /* - relational_expression - : shift_expression - | relational_expression '<' shift_expression - | relational_expression '>' shift_expression - | relational_expression LE_OP shift_expression - | relational_expression GE_OP shift_expression - ; - */ - let op = rp::or!( - rp::one(Token::LessThan).output(BinaryOperator::LessThan), - rp::one(Token::GreaterThan).output(BinaryOperator::GreaterThan), - rp::one(Token::LeOp).output(BinaryOperator::LessThanOrEqual), - rp::one(Token::GeOp).output(BinaryOperator::GreaterThanOrEqual) - ); - let relational = shift_expression.clone().reduce_left( - rp::seq!(op, shift_expression.clone()), - |lhs: Expression, op: BinaryOperator, rhs: Expression| -> Expression { - Expression::Comparison(ExprComparison { - op, - lhs: Box::new(lhs), - rhs: Box::new(rhs), - }) - }, - ); - relational_expression.borrow_mut().assign(relational); - } - { - /* - equality_expression - : relational_expression - | equality_expression EQ_OP relational_expression - | equality_expression NE_OP relational_expression - ; - */ - let op = rp::or!( - rp::one(Token::EqOp).output(BinaryOperator::Equal), - rp::one(Token::NeOp).output(BinaryOperator::NotEqual) - ); - let equality = relational_expression.clone().reduce_left( - rp::seq!(op, relational_expression.clone()), - |lhs: Expression, op: BinaryOperator, rhs: Expression| -> Expression { - Expression::Comparison(ExprComparison { - op, - lhs: Box::new(lhs), - rhs: Box::new(rhs), - }) - }, - ); - equality_expression.borrow_mut().assign(equality); - } - { - /* - and_expression - : equality_expression - | and_expression '&' equality_expression - ; - */ - let op = rp::one(Token::Ampersand).output(BinaryOperator::BitwiseAnd); - let and = equality_expression.clone().reduce_left( - rp::seq!(op, equality_expression.clone()), - |lhs: Expression, op: BinaryOperator, rhs: Expression| -> Expression { - Expression::Bitwise(ExprBitwise { - op, - lhs: Box::new(lhs), - rhs: Box::new(rhs), - }) - }, - ); - and_expression.borrow_mut().assign(and); - } - { - /* - exclusive_or_expression - : and_expression - | exclusive_or_expression '^' and_expression - ; - */ - let op = rp::one(Token::Caret).output(BinaryOperator::BitwiseXor); - let xor = and_expression.clone().reduce_left( - rp::seq!(op, and_expression.clone()), - |lhs: Expression, op: BinaryOperator, rhs: Expression| -> Expression { - Expression::Bitwise(ExprBitwise { - op, - lhs: Box::new(lhs), - rhs: Box::new(rhs), - }) - }, - ); - exclusive_or_expression.borrow_mut().assign(xor); - } - { - /* - inclusive_or_expression - : exclusive_or_expression - | inclusive_or_expression '|' exclusive_or_expression - ; - */ - let op = rp::one(Token::Pipe).output(BinaryOperator::BitwiseOr); - let or = exclusive_or_expression.clone().reduce_left( - rp::seq!(op, exclusive_or_expression.clone()), - |lhs: Expression, op: BinaryOperator, rhs: Expression| -> Expression { - Expression::Bitwise(ExprBitwise { - op, - lhs: Box::new(lhs), - rhs: Box::new(rhs), - }) - }, - ); - inclusive_or_expression.borrow_mut().assign(or); - } - { - /* - logical_and_expression - : inclusive_or_expression - | logical_and_expression AND_OP inclusive_or_expression - ; - */ - let op = rp::one(Token::AndOp).output(BinaryOperator::LogicalAnd); - let logical_and = inclusive_or_expression.clone().reduce_left( - rp::seq!(op, inclusive_or_expression.clone()), - |lhs: Expression, op: BinaryOperator, rhs: Expression| -> Expression { - Expression::LogicalBinary(ExprLogicalBinary { - op, - lhs: Box::new(lhs), - rhs: Box::new(rhs), - }) - }, - ); - logical_and_expression.borrow_mut().assign(logical_and); - } - { - /* - logical_or_expression - : logical_and_expression - | logical_or_expression OR_OP logical_and_expression - ; - */ - - let op = rp::one(Token::OrOp).output(BinaryOperator::LogicalOr); - let logical_or = logical_and_expression.clone().reduce_left( - rp::seq!(op, logical_and_expression.clone()), - |lhs: Expression, op: BinaryOperator, rhs: Expression| -> Expression { - Expression::LogicalBinary(ExprLogicalBinary { - op, - lhs: Box::new(lhs), - rhs: Box::new(rhs), - }) - }, - ); - logical_or_expression.borrow_mut().assign(logical_or); - } - { - /* - conditional_expression - : logical_or_expression - | logical_or_expression '?' expression ':' conditional_expression - ; - */ - let conditional = rp::seq!( - logical_or_expression.clone(), - rp::seq!( - rp::one(Token::Question).void(), - self.expression.clone().or_else(|| -> Expression { - panic!("Invalid expression after '?' in conditional expression"); - }), - rp::one(Token::Colon).void().or_else(|| -> () { - panic!("Colon ':' expected after '?' in conditional expression"); - }), - conditional_expression.clone().or_else(|| -> Expression { - panic!("Invalid expression after ':' in conditional expression"); - }) - ) - .optional() - ) - .map( - |cond: Expression, truefalse: Option<(Expression, Expression)>| -> Expression { - if let Some((true_expr, false_expr)) = truefalse { - Expression::Conditional(ExprConditional { - cond: Box::new(cond), - then_expr: Box::new(true_expr), - else_expr: Box::new(false_expr), - }) - } else { - cond - } - }, - ); - conditional_expression.borrow_mut().assign(conditional); - self.constant_expression - .borrow_mut() - .assign(conditional_expression.clone()); - } - { - /* - assignment_operator - : '=' - | MUL_ASSIGN - | DIV_ASSIGN - | MOD_ASSIGN - | ADD_ASSIGN - | SUB_ASSIGN - | LEFT_ASSIGN - | RIGHT_ASSIGN - | AND_ASSIGN - | XOR_ASSIGN - | OR_ASSIGN - ; - */ - let assignment_operator = rp::or!( - rp::one(Token::Equal).output(BinaryOperator::Assign), - rp::one(Token::MulAssign).output(BinaryOperator::MulAssign), - rp::one(Token::DivAssign).output(BinaryOperator::DivAssign), - rp::one(Token::ModAssign).output(BinaryOperator::ModAssign), - rp::one(Token::AddAssign).output(BinaryOperator::AddAssign), - rp::one(Token::SubAssign).output(BinaryOperator::SubAssign), - rp::one(Token::LeftAssign).output(BinaryOperator::ShiftLeftAssign), - rp::one(Token::RightAssign).output(BinaryOperator::ShiftRightAssign), - rp::one(Token::AndAssign).output(BinaryOperator::BitwiseAndAssign), - rp::one(Token::XorAssign).output(BinaryOperator::BitwiseXorAssign), - rp::one(Token::OrAssign).output(BinaryOperator::BitwiseOrAssign) - ); - /* - assignment_expression - : conditional_expression - | unary_expression assignment_operator assignment_expression - */ - let assignment = rp::or!( - rp::seq!( - unary_expression.clone(), - assignment_operator, - self.assignment_expression.clone() - ) - .map( - |lhs: Expression, op: BinaryOperator, rhs: Expression| -> Expression { - if op == BinaryOperator::Assign { - Expression::Assign(ExprAssign { - lhs: Box::new(lhs), - rhs: Box::new(rhs), - }) - } else { - Expression::AssignOp(ExprAssignOp { - op, - lhs: Box::new(lhs), - rhs: Box::new(rhs), - }) - } - } - ), - conditional_expression.clone() - ); - self.assignment_expression.borrow_mut().assign(assignment); - } - { - /* - expression - : assignment_expression - | expression ',' assignment_expression - ; - */ - let expression = self.assignment_expression.clone().reduce_left( - rp::seq!(rp::one(Token::Comma).void(), self.expression.clone()), - |lhs: Expression, rhs: Expression| -> Expression { - Expression::Comma(ExprComma { - lhs: Box::new(lhs), - rhs: Box::new(rhs), - }) - }, - ); - self.expression.borrow_mut().assign(expression); - } - - { - /* - initializer - : assignment_expression - | '{' initializer_list '}' - | '{' initializer_list ',' '}' - ; - - initializer_list - : initializer - | initializer_list ',' initializer - ; - */ - let initalizer_list = self - .initializer - .clone() - .map(|e: Expression| -> Vec { - let mut ret = Vec::new(); - ret.push(e); - ret - }) - .reduce_left( - rp::seq!(rp::one(Token::Comma).void(), self.initializer.clone()), - |mut v: Vec, e: Expression| -> Vec { - v.push(e); - v - }, - ) - .map(|v: Vec| -> Expression { - Expression::InitializerList(ExprInitializerList { initializers: v }) - }); - - let initializer_ = rp::or!( - rp::seq!( - rp::one(Token::LeftBrace).void(), - initalizer_list, - rp::one(Token::Comma).optional().void(), - rp::one(Token::RightBrace).void() - ), - self.assignment_expression.clone() - ); - self.initializer.borrow_mut().assign(initializer_); - } - } - - fn declarator(&mut self) { - let identifier = rp::check(|t: Token| -> Option { - if let Token::Identifier(s) = t { - Some(s) - } else { - None - } - }); - - /* - direct_declarator - : IDENTIFIER - | '(' declarator ')' - | direct_declarator '[' constant_expression ']' - | direct_declarator '[' ']' - | direct_declarator '(' parameter_type_list ')' - | direct_declarator '(' ')' - ; - */ - let direct_declarator_leaf = rp::or!( - identifier.clone().map(|s: String| -> Declarator { - Declarator::Identifier(DeclIdentifier { name: s }) - }), - rp::seq!( - rp::one(Token::LeftParen).void(), - self.declarator.clone(), - rp::one(Token::RightParen).void() - ) - ); - enum DirectDeclaratorType { - Array(Option), // length - Function(Vec<(Option, TypeInfo)>), // parameters - } - let direct_declarator = direct_declarator_leaf.reduce_left( - rp::or!( - rp::seq!( - rp::one(Token::LeftBracket).void(), - self.constant_expression.clone(), - rp::one(Token::RightBracket).void() - ) - .map(|len: Expression| -> DirectDeclaratorType { - DirectDeclaratorType::Array(Some(len)) - }), - rp::seq!( - rp::one(Token::LeftBracket).void(), - rp::one(Token::RightBracket).void() - ) - .map(|| -> DirectDeclaratorType { DirectDeclaratorType::Array(None) }), - rp::seq!( - rp::one(Token::LeftParen).void(), - rp::one(Token::RightParen).void() - ) - .map(|| -> DirectDeclaratorType { DirectDeclaratorType::Function(Vec::new()) }), - rp::seq!( - rp::one(Token::LeftParen).void(), - self.parameter_list.clone(), - rp::one(Token::RightParen).void() - ) - .map( - |params: Vec<(Option, TypeInfo)>| -> DirectDeclaratorType { - DirectDeclaratorType::Function(params) - } - ) - ), - |lhs: Declarator, op: DirectDeclaratorType| -> Declarator { - match op { - DirectDeclaratorType::Array(Some(len)) => { - Declarator::DirectArrayFixed(DeclDirectArrayFixed { - declarator: Box::new(lhs), - size: len, - }) - } - DirectDeclaratorType::Array(None) => { - Declarator::DirectArrayUnbounded(DeclDirectArrayUnbounded { - declarator: Box::new(lhs), - }) - } - DirectDeclaratorType::Function(params) => { - Declarator::DirectFunction(DeclDirectFunction { - declarator: Box::new(lhs), - params, - }) - } - } - }, - ); - /* - pointer - : '*' - | '*' CONST pointer - | '*' CONST - | '*' pointer - ; - */ - let pointer_ = rp::seq!( - rp::one(Token::Star).void(), - rp::or!( - rp::seq!(rp::one(Token::Const).void(), self.pointer.clone()).map( - |mut decorators: Vec| -> Vec { - let mut ret = Vec::new(); - ret.push(Token::Const); - ret.append(&mut decorators); - ret - } - ), - rp::one(Token::Const).map(|t| -> Vec { vec![t] }), - self.pointer.clone() - ) - .optional() - ) - .map(|decorators: Option>| -> Vec { - if let Some(mut decorators) = decorators { - let mut ret = Vec::new(); - ret.push(Token::Star); - ret.append(&mut decorators); - ret - } else { - vec![Token::Star] - } - }); - self.pointer.borrow_mut().assign(pointer_); - - /* - declarator - : pointer direct_declarator - | direct_declarator - ; - */ - - let declarator_ = rp::or!( - rp::seq!(self.pointer.clone(), direct_declarator.clone()).map( - |ptr: Vec, mut decl: Declarator| -> Declarator { - for t in ptr.iter() { - match t { - Token::Star => { - decl = Declarator::Pointer(DeclPointer { - declarator: Box::new(decl), - }) - } - Token::Const => { - decl = Declarator::Const(DeclConst { - declarator: Box::new(decl), - }) - } - _ => unreachable!("Invalid token in pointer or const"), - } - } - decl - } - ), - direct_declarator.clone() - ); - - self.declarator.borrow_mut().assign(declarator_); - - /* - init_declarator - : declarator - | declarator '=' initializer - ; - */ - let init_declarator_ = rp::seq!( - self.declarator.clone(), - rp::seq!(rp::one(Token::Equal).void(), self.initializer.clone()).optional() - ) - .map(|decl: Declarator, init: Option| -> DeclInit { - DeclInit { - declarator: Box::new(decl), - initializer: init, - } - }); - self.init_declarator.borrow_mut().assign(init_declarator_); - { - /* - - direct_abstract_declarator - : '(' abstract_declarator ')' - | '[' ']' - | '[' constant_expression ']' - | direct_abstract_declarator '[' ']' - | direct_abstract_declarator '[' constant_expression ']' - | '(' ')' - | '(' parameter_type_list ')' - | direct_abstract_declarator '(' ')' - | direct_abstract_declarator '(' parameter_type_list ')' - ; - */ - - enum DirectAbstractDeclaratorLeaf { - Array(Option), - Function(Vec<(Option, TypeInfo)>), - } - let direct_abstract_declarator: Rc>> = - Default::default(); - - let direct_abstract_declarator_leaf_array = rp::or!( - rp::seq!( - rp::one(Token::LeftBracket).void(), - rp::one(Token::RightBracket).void() - ) - .map(|| -> DirectAbstractDeclaratorLeaf { - DirectAbstractDeclaratorLeaf::Array(None) - }), - rp::seq!( - rp::one(Token::LeftBracket).void(), - self.constant_expression.clone(), - rp::one(Token::RightBracket).void() - ) - .map(|len: Expression| -> DirectAbstractDeclaratorLeaf { - DirectAbstractDeclaratorLeaf::Array(Some(len)) - }) - ); - let direct_abstract_declarator_leaf_function = rp::or!( - rp::seq!( - rp::one(Token::LeftParen).void(), - rp::one(Token::RightParen).void() - ) - .map(|| -> DirectAbstractDeclaratorLeaf { - DirectAbstractDeclaratorLeaf::Function(Vec::new()) - }), - rp::seq!( - rp::one(Token::LeftParen).void(), - self.parameter_list.clone(), - rp::one(Token::RightParen).void() - ) - .map( - |params: Vec<(Option, TypeInfo)>| -> DirectAbstractDeclaratorLeaf { - DirectAbstractDeclaratorLeaf::Function(params) - } - ) - ); - let direct_abstract_declarator_leaf_paren = rp::seq!( - rp::one(Token::LeftParen).void(), - direct_abstract_declarator.clone(), - rp::one(Token::RightParen).void() - ); - let direct_abstract_declarator_decorator = rp::or!( - direct_abstract_declarator_leaf_array, - direct_abstract_declarator_leaf_function - ); - - let direct_abstract_declarator_leaf = rp::or!( - direct_abstract_declarator_leaf_paren, - direct_abstract_declarator_decorator.clone().map( - |op: DirectAbstractDeclaratorLeaf| -> Declarator { - match op { - DirectAbstractDeclaratorLeaf::Array(len) => { - if let Some(len) = len { - Declarator::AbstractArrayFixed(DeclAbstractArrayFixed { - declarator: None, - size: len, - }) - } else { - Declarator::AbstractArrayUnbounded(DeclAbstractArrayUnbounded { - declarator: None, - }) - } - } - DirectAbstractDeclaratorLeaf::Function(params) => { - Declarator::AbstractFunction(DeclAbstractFunction { - declarator: None, - params, - }) - } - } - }, - ) - ); - - let direct_abstract_declarator_ = direct_abstract_declarator_leaf.reduce_left( - direct_abstract_declarator_decorator, - |lhs: Declarator, op: DirectAbstractDeclaratorLeaf| -> Declarator { - match op { - DirectAbstractDeclaratorLeaf::Array(len) => { - if let Some(len) = len { - Declarator::AbstractArrayFixed(DeclAbstractArrayFixed { - declarator: Some(Box::new(lhs)), - size: len, - }) - } else { - Declarator::AbstractArrayUnbounded(DeclAbstractArrayUnbounded { - declarator: Some(Box::new(lhs)), - }) - } - } - DirectAbstractDeclaratorLeaf::Function(params) => { - Declarator::AbstractFunction(DeclAbstractFunction { - declarator: Some(Box::new(lhs)), - params, - }) - } - } - }, - ); - direct_abstract_declarator - .borrow_mut() - .assign(direct_abstract_declarator_); - /* - abstract_declarator - : pointer - | direct_abstract_declarator - | pointer direct_abstract_declarator - ; - */ - let pointered = rp::seq!( - self.pointer.clone(), - direct_abstract_declarator.clone().optional() - ) - .map(|ptr: Vec, decl: Option| -> Declarator { - let mut decl = decl; - for t in ptr.iter() { - match t { - Token::Star => { - decl = Some(Declarator::AbstractPointer(DeclAbstractPointer { - declarator: decl.map(Box::new), - })); - } - Token::Const => { - decl = Some(Declarator::AbstractConst(DeclAbstractConst { - declarator: decl.map(Box::new), - })); - } - _ => unreachable!("Invalid token in pointer"), - } - } - decl.unwrap() - }); - let abstract_declarator_ = rp::or!(pointered, direct_abstract_declarator.clone()); - self.abstract_declarator - .borrow_mut() - .assign(abstract_declarator_); - } - } - - fn statement_parser(&mut self) { - let identifier = rp::check(|t: Token| -> Option { - if let Token::Identifier(s) = t { - Some(s) - } else { - None - } - }); - let labeled_statement: Rc>> = - Default::default(); - let expression_statement: Rc>> = - Default::default(); - let selection_statement: Rc>> = - Default::default(); - let iteration_statement: Rc>> = - Default::default(); - let jump_statement: Rc>> = Default::default(); - - { - let parameter_declaration = rp::seq!( - self.type_specifier.clone(), - rp::or!(self.declarator.clone(), self.abstract_declarator.clone()).optional() - ); - - let parameter_list_ = parameter_declaration - .clone() - .map( - |typeinfo: TypeInfo, - declarator: Option| - -> Vec<(TypeInfo, Option)> { - vec![(typeinfo, declarator)] - }, - ) - .reduce_left( - rp::seq!(rp::one(Token::Comma).void(), parameter_declaration), - |mut v: Vec<(TypeInfo, Option)>, - typeinfo: TypeInfo, - declarator: Option| - -> Vec<(TypeInfo, Option)> { - v.push((typeinfo, declarator)); - v - }, - ) - .map( - |v: Vec<(TypeInfo, Option)>| -> Vec<(Option, TypeInfo)> { - let mut ret = Vec::new(); - for (typeinfo, declarator) in v.into_iter() { - if let Some(declarator) = declarator { - let (name, typeinfo_) = - declarator.resolve_typeinfo(typeinfo.clone()); - ret.push((name, typeinfo_)); - } else { - ret.push((None, typeinfo)); - } - } - ret - }, - ); - self.parameter_list.borrow_mut().assign(parameter_list_); - } - { - /* - statement - : labeled_statement - | compound_statement - | expression_statement - | selection_statement - | iteration_statement - | jump_statement - | declaration - ; - */ - let statement = rp::or!( - expression_statement.clone().map(|expr| -> Statement { - Statement::Expression(StmtExpression { expression: expr }) - }), - self.declaration.clone(), - labeled_statement.clone(), - self.compound_statement.clone(), - selection_statement.clone(), - iteration_statement.clone(), - jump_statement.clone() - ); - self.statement.borrow_mut().assign(statement); - } - { - /* - labeled_statement - : IDENTIFIER ':' statement - | CASE constant_expression ':' statement - | DEFAULT ':' statement - ; - */ - let labeled_statement_ = rp::or!( - rp::seq!( - identifier, - rp::one(Token::Colon).void(), - self.statement.clone().or_else(|| -> Statement { - panic!("Invalid Statement after label"); - }) - ) - .map(|s: String, stmt: Statement| -> Statement { - Statement::Labeled(StmtLabeled { - label: s, - statement: Box::new(stmt), - }) - }), - rp::seq!( - rp::one(Token::Case).void(), - self.constant_expression.clone().or_else(|| -> Expression { - panic!("Invalid expression after 'case'"); - }), - rp::one(Token::Colon).void().or_else(|| -> () { - panic!(": is expected after 'case'"); - }), - self.statement.clone().or_else(|| -> Statement { - panic!("Invalid Statement after 'case'"); - }) - ) - .map(|expr: Expression, stmt: Statement| -> Statement { - Statement::Case(StmtCase { - value: expr, - statement: Box::new(stmt), - }) - }), - rp::seq!( - rp::one(Token::Default).void(), - rp::one(Token::Colon).void().or_else(|| -> () { - panic!(": is expected after 'default'"); - }), - self.statement.clone().or_else(|| -> Statement { - panic!("Invalid Statement after 'default'"); - }) - ) - .map(|stmt: Statement| -> Statement { - Statement::Default(StmtDefault { - statement: Box::new(stmt), - }) - }) - ); - labeled_statement.borrow_mut().assign(labeled_statement_); - } - { - /* - compound_statement - : '{' statement* '}' - ; - */ - - let compound_statement_ = rp::seq!( - rp::one(Token::LeftBrace).void(), - self.statement - .clone() - .repeat(0..) - .map(|compound: Vec| -> Statement { - Statement::Compound(StmtCompound { - statements: compound, - }) - }), - rp::one(Token::RightBrace).void() - ); - self.compound_statement - .borrow_mut() - .assign(compound_statement_); - } - { - /* - expression_statement - : ';' - | expression ';' - ; - */ - - let expression_statement_ = rp::seq!( - self.expression.clone().optional(), - rp::one(Token::SemiColon).void() - ) - .map(|expr: Option| -> Expression { - if let Some(expr) = expr { - expr - } else { - Expression::Void(ExprVoid {}) - } - }); - expression_statement - .borrow_mut() - .assign(expression_statement_); - } - { - /* - selection_statement - : IF '(' expression ')' statement - | IF '(' expression ')' statement ELSE statement - | SWITCH '(' expression ')' statement - ; - */ - let selection_statement_ = rp::or!( - rp::seq!( - rp::one(Token::If).void(), - rp::one(Token::LeftParen).void().or_else(|| -> () { - panic!("'(' is expected after 'if'"); - }), - self.expression.clone().or_else(|| -> Expression { - panic!("Invalid expression after 'if'"); - }), - rp::one(Token::RightParen).void().or_else(|| -> () { - panic!("')' is expected after 'if'"); - }), - self.statement.clone().or_else(|| -> Statement { - panic!("Invalid body statement after 'if'"); - }), - rp::seq!( - rp::one(Token::Else).void(), - self.statement.clone().or_else(|| -> Statement { - panic!("Invalid body statement after 'else'"); - }) - ) - .optional() - ) - .map( - |cond: Expression, - stmt: Statement, - else_stmt: Option| - -> Statement { - Statement::If(StmtIf { - cond, - then_statement: Box::new(stmt), - else_statement: else_stmt.map(Box::new), - }) - } - ), - rp::seq!( - rp::one(Token::Switch).void(), - rp::one(Token::LeftParen).void().or_else(|| -> () { - panic!("'(' is expected after 'switch'"); - }), - self.expression.clone().or_else(|| -> Expression { - panic!("Invalid expression after 'switch'"); - }), - rp::one(Token::RightParen).void().or_else(|| -> () { - panic!("')' is expected after 'switch'"); - }), - self.statement.clone().or_else(|| -> Statement { - panic!("Invalid body statement after 'switch'"); - }) - ) - .map(|target: Expression, stmt: Statement| -> Statement { - Statement::Switch(StmtSwitch { - target, - statement: Box::new(stmt), - }) - }) - ); - selection_statement - .borrow_mut() - .assign(selection_statement_); - } - { - /* - iteration_statement - : WHILE '(' expression ')' statement - | DO statement WHILE '(' expression ')' ';' - | FOR '(' expression_statement expression_statement ')' statement - | FOR '(' expression_statement expression_statement expression ')' statement - ; - */ - - let while_statement = rp::seq!( - rp::one(Token::While).void(), - rp::one(Token::LeftParen).void().or_else(|| -> () { - panic!("'(' is expected after 'while'"); - }), - self.expression.clone().or_else(|| -> Expression { - panic!("Invalid expression after 'while'"); - }), - rp::one(Token::RightParen).void().or_else(|| -> () { - panic!("')' is expected after 'while'"); - }), - self.statement.clone().or_else(|| -> Statement { - panic!("Invalid body statement after 'while'"); - }) - ) - .map(|cond: Expression, stmt: Statement| -> Statement { - Statement::While(StmtWhile { - cond, - statement: Box::new(stmt), - }) - }); - - let do_while_statement = rp::seq!( - rp::one(Token::Do).void(), - self.statement.clone().or_else(|| -> Statement { - panic!("Invalid body statement for 'do-while'"); - }), - rp::one(Token::While).void(), - rp::one(Token::LeftParen).void().or_else(|| -> () { - panic!("'(' is expected after 'do-while'"); - }), - self.expression.clone().or_else(|| -> Expression { - panic!("Invalid expression after 'do-while'"); - }), - rp::one(Token::RightParen).void().or_else(|| -> () { - panic!("')' is expected after 'do-while'"); - }), - rp::one(Token::SemiColon).void().or_else(|| -> () { - panic!("';' is expected after 'do-while'"); - }) - ) - .map(|stmt: Statement, cond: Expression| -> Statement { - Statement::DoWhile(StmtDoWhile { - cond, - statement: Box::new(stmt), - }) - }); - - let for_statement = rp::seq!( - rp::one(Token::For).void(), - rp::one(Token::LeftParen).void().or_else(|| -> () { - panic!("'(' is expected after 'for'"); - }), - expression_statement.clone().or_else(|| -> Expression { - panic!("Invalid 1st statement for 'for' statement"); - }), - expression_statement.clone().or_else(|| -> Expression { - panic!("Invalid 2nd statement for 'for' statement"); - }), - self.expression.clone().optional(), - rp::one(Token::RightParen).void().or_else(|| -> () { - panic!("')' is expected after 'for'"); - }), - self.statement.clone().or_else(|| -> Statement { - panic!("Invalid body statement for 'for' statement"); - }) - ) - .map( - |init: Expression, - cond: Expression, - next: Option, - stmt: Statement| - -> Statement { - Statement::For(StmtFor { - init, - cond, - next, - statement: Box::new(stmt), - }) - }, - ); - - let iteration_statement_ = rp::or!(while_statement, do_while_statement, for_statement); - iteration_statement - .borrow_mut() - .assign(iteration_statement_); - } - - { - /* - jump_statement - : GOTO IDENTIFIER ';' - | CONTINUE ';' - | BREAK ';' - | RETURN ';' - | RETURN expression ';' - ; - */ - - let goto_statement = rp::seq!( - rp::one(Token::Goto).void(), - identifier.or_else(|| -> String { - panic!("IDENTIFIER label must be followed by 'goto'"); - }), - rp::one(Token::SemiColon).void().or_else(|| -> () { - panic!("';' is expected after 'goto'"); - }) - ) - .map(|s: String| -> Statement { Statement::Goto(StmtGoto { label: s }) }); - - let continue_statement = rp::seq!( - rp::one(Token::Continue).void(), - rp::one(Token::SemiColon).void().or_else(|| -> () { - panic!("';' is expected after 'continue'"); - }) - ) - .map(|| -> Statement { Statement::Continue(StmtContinue {}) }); - - let break_statement = rp::seq!( - rp::one(Token::Break).void(), - rp::one(Token::SemiColon).void().or_else(|| -> () { - panic!("';' is expected after 'break'"); - }) - ) - .map(|| -> Statement { Statement::Break(StmtBreak {}) }); - - let return_statement = rp::seq!( - rp::one(Token::Return).void(), - self.expression.clone().optional(), - rp::one(Token::SemiColon).void().or_else(|| -> () { - panic!("';' is expected after 'return'"); - }) - ) - .map(|expr: Option| -> Statement { - Statement::Return(StmtReturn { expr }) - }); - - let jump_statement_ = rp::or!( - goto_statement, - continue_statement, - break_statement, - return_statement - ); - - jump_statement.borrow_mut().assign(jump_statement_); - } - - { - /* - init_declarator_list - : init_declarator - | init_declarator_list ',' init_declarator - ; - */ - let init_declarator_list = self - .init_declarator - .clone() - .map(|e: DeclInit| -> Vec { - let mut ret = Vec::new(); - ret.push(e); - ret - }) - .reduce_left( - rp::seq!(rp::one(Token::Comma).void(), self.init_declarator.clone()), - |mut v: Vec, e: DeclInit| -> Vec { - v.push(e); - v - }, - ); - /* - declaration - : specifier_list ';' - | specifier_list init_declarator_list ';' - | TYPEDEF specifier_list init_declarator_list ';' - ; - */ - let declaration = rp::seq!( - self.type_specifier.clone(), - init_declarator_list.clone().optional(), - rp::one(Token::SemiColon).void() - ) - .map( - |typeinfo: TypeInfo, decls: Option>| -> Statement { - if let Some(decls) = decls { - // variable definition - let mut ret = Vec::with_capacity(decls.len()); - for decl in decls.into_iter() { - let (name, typeinfo_) = decl.resolve_typeinfo(typeinfo.clone()); - ret.push(( - name.expect("Declaration must have name"), - typeinfo_, - decl.initializer, - )); - } - // check if it's a function declaration - if ret.len() == 1 { - if let TypeInfo::Function(return_type, params) = &ret[0].1 { - return Statement::FunctionDeclaration(StmtFunctionDeclaration { - name: ret[0].0.clone(), - return_type: *return_type.clone(), - params: params.clone(), - }); - } - } - Statement::Declaration(StmtDeclaration { vars: ret }) - } else { - // type definition - Statement::StructDefinition(StmtStructDefinition { typeinfo }) - } - }, - ); - let typedef_declaration = rp::seq!( - rp::one(Token::Typedef).void(), - self.type_specifier.clone().or_else(|| -> TypeInfo { - panic!("Typedef must have a type specifier"); - }), - init_declarator_list.clone().or_else(|| -> Vec { - panic!("Typedef must have a declarator"); - }), - rp::one(Token::SemiColon).void().or_else(|| -> () { - panic!("';' is expected after 'typedef'"); - }) - ) - .map(|typeinfo: TypeInfo, decls: Vec| -> Statement { - if decls.len() != 1 { - panic!("Typedef declaration must have exactly one declarator"); - } - let decl = &decls[0]; - if decl.initializer.is_some() { - panic!("Typedef declaration cannot have initializer"); - } - let (name, typeinfo) = decl.declarator.resolve_typeinfo(typeinfo); - - Statement::Typedef(StmtTypedef { - name: name.expect("Typedef must have a target name"), - typeinfo, - }) - }); - self.declaration - .borrow_mut() - .assign(rp::or!(declaration, typedef_declaration)); - } - } - - fn translation_unit_parser(&mut self) { - let function_definition: Rc>> = - Default::default(); - { - /* - translation_unit - : external_declaration - | translation_unit external_declaration - ; - */ - - /* - external_declaration - : function_definition - | declaration - ; - */ - let external_declaration = - rp::or!(function_definition.clone(), self.declaration.clone()); - - let translation_unit_ = - external_declaration - .repeat(1..) - .map(|decls: Vec| -> TranslationUnit { - TranslationUnit { statements: decls } - }); - self.translation_unit.borrow_mut().assign(translation_unit_); - } - { - /* - function_definition - : specifier_list declarator compound_statement - | declarator compound_statement - ; - ; - */ - - let funcdef = rp::seq!( - self.type_specifier.clone().optional(), - self.declarator.clone(), - self.compound_statement.clone() - ) - .map( - |returntype: Option, - decl: Declarator, - stmt: Statement| - -> Statement { - let direct_func_decl = match decl { - Declarator::DirectFunction(direct_func_decl) => direct_func_decl, - _ => { - unreachable!("Function definition must have a function declarator"); - } - }; - let name = match &*direct_func_decl.declarator { - Declarator::Identifier(decl) => decl.name.clone(), - _ => { - unreachable!("Function definition must have a function declarator with an identifier"); - } - }; - Statement::FunctionDefinition(StmtFunctionDefinition{ - return_type: returntype.or(Some(TypeInfo::Void)).unwrap(), - name: name.clone(), - params: direct_func_decl.params.clone(), - body: Box::new(stmt), - }) - }, - ); - - function_definition.borrow_mut().assign(funcdef); - } - } -} diff --git a/src/ast/parser_lr.rs b/src/ast/parser_lr.rs new file mode 100644 index 0000000..390155b --- /dev/null +++ b/src/ast/parser_lr.rs @@ -0,0 +1,1237 @@ +use rusty_lr::lr1; + +use super::declarator; +use super::declarator::Declarator; +use super::expression; +use super::expression::Expression; +use super::statement; +use super::statement::Statement; + +use crate::token::Token; + +lr1! { +%lalr; + +%tokentype Token; + +%token ident Token::Identifier("".to_string()); +%token lparen Token::LeftParen; +%token rparen Token::RightParen; +%token string_literal Token::StringLiteral("".to_string()); +%token constant_character Token::ConstantCharacter(0); +%token constant_integer Token::ConstantInteger(0); +%token constant_long Token::ConstantLong(0); +%token constant_unsigned_integer Token::ConstantUnsignedInteger(0); +%token constant_unsigned_long Token::ConstantUnsignedLong(0); +%token constant_float Token::ConstantFloat(0.0); +%token constant_double Token::ConstantDouble(0.0); +%token lbracket Token::LeftBracket; +%token rbracket Token::RightBracket; +%token lbrace Token::LeftBrace; +%token rbrace Token::RightBrace; +%token comma Token::Comma; +%token semicolon Token::SemiColon; +%token ellipsis Token::Ellipsis; +%token question Token::Question; +%token colon Token::Colon; +%token dot Token::Dot; +%token ptr_op Token::PtrOp; +%token inc_op Token::IncOp; +%token dec_op Token::DecOp; +%token sizeof Token::Sizeof; +%token ampersand Token::Ampersand; +%token exclamation Token::Exclamation; +%token tilde Token::Tilde; +%token minus Token::Minus; +%token plus Token::Plus; +%token star Token::Star; +%token slash Token::Slash; +%token percent Token::Percent; +%token left_op Token::LeftOp; +%token right_op Token::RightOp; +%token less Token::LessThan; +%token greater Token::GreaterThan; +%token caret Token::Caret; +%token pipe Token::Pipe; +%token le Token::LeOp; +%token ge Token::GeOp; +%token eq Token::EqOp; +%token ne Token::NeOp; +%token and_op Token::AndOp; +%token or_op Token::OrOp; +%token assign Token::Equal; +%token mul_assign Token::MulAssign; +%token div_assign Token::DivAssign; +%token mod_assign Token::ModAssign; +%token add_assign Token::AddAssign; +%token sub_assign Token::SubAssign; +%token left_assign Token::LeftAssign; +%token right_assign Token::RightAssign; +%token and_assign Token::AndAssign; +%token xor_assign Token::XorAssign; +%token or_assign Token::OrAssign; +%token case Token::Case; +%token default Token::Default; +%token if_ Token::If; +%token else_ Token::Else; +%token switch Token::Switch; +%token while_ Token::While; +%token do_ Token::Do; +%token for_ Token::For; +%token goto_ Token::Goto; +%token continue_ Token::Continue; +%token break_ Token::Break; +%token return_ Token::Return; +%token typedef Token::Typedef; +%token extern_ Token::Extern; +%token static_ Token::Static; +%token auto Token::Auto; +%token register Token::Register; +%token const_ Token::Const; +%token volatile Token::Volatile; +%token void_ Token::Void; +%token char_ Token::Char; +%token short_ Token::Short; +%token int_ Token::Int; +%token long_ Token::Long; +%token float_ Token::Float; +%token double_ Token::Double; +%token signed Token::Signed; +%token unsigned Token::Unsigned; +%token struct_ Token::Struct; +%token union_ Token::Union; +%token enum_ Token::Enum; +%eof Token::Eof; + +%left else_; + +%start translation_unit; + + +Constant(Expression) + : constant_character { + if let Token::ConstantCharacter(value) = constant_character { + Expression::ConstantCharacter(expression::ExprConstantCharacter{ value }) + } else { + unreachable!() + } + } + | constant_integer { + if let Token::ConstantInteger(value) = constant_integer { + Expression::ConstantInteger(expression::ExprConstantInteger{ value }) + } else { + unreachable!() + } + } + | constant_long { + if let Token::ConstantLong(value) = constant_long { + Expression::ConstantLong(expression::ExprConstantLong{ value }) + } else { + unreachable!() + } + } + | constant_unsigned_integer { + if let Token::ConstantUnsignedInteger(value) = constant_unsigned_integer { + Expression::ConstantUnsignedInteger(expression::ExprConstantUnsignedInteger{ value }) + } else { + unreachable!() + } + } + | constant_unsigned_long { + if let Token::ConstantUnsignedLong(value) = constant_unsigned_long { + Expression::ConstantUnsignedLong(expression::ExprConstantUnsignedLong{ value }) + } else { + unreachable!() + } + } + | constant_float { + if let Token::ConstantFloat(value) = constant_float { + Expression::ConstantFloat(expression::ExprConstantFloat{ value }) + } else { + unreachable!() + } + } + | constant_double { + if let Token::ConstantDouble(value) = constant_double { + Expression::ConstantDouble(expression::ExprConstantDouble{ value }) + } else { + unreachable!() + } + } + ; + + +primary_expression(Expression) + : ident { + if let Token::Identifier(name) = ident { + Expression::Identifier(expression::ExprIdentifier{ name }) + } else { + unreachable!() + } + } + | Constant + | string_literal { + if let Token::StringLiteral(value) = string_literal { + Expression::String(expression::ExprString { value }) + } else { + unreachable!() + } + } + | lparen! expression rparen! + ; + + +postfix_expression(Expression) + : primary_expression + | postfix_expression lbracket! expression rbracket! { + Expression::Bracket(expression::ExprBracket{ + src: Box::new(postfix_expression), + index: Box::new(expression), + }) + } + | postfix_expression lparen rparen { + Expression::Paren(expression::ExprParen{ + src: Box::new(postfix_expression), + args: Vec::new(), + }) + } + | postfix_expression lparen! argument_expression_list rparen! { + Expression::Paren(expression::ExprParen{ + src: Box::new(postfix_expression), + args: argument_expression_list, + }) + } + | postfix_expression dot! ident { + if let Token::Identifier(name) = ident { + Expression::Member(expression::ExprMember{ + src: Box::new(postfix_expression), + member: name, + }) + } else { + unreachable!() + } + } + | postfix_expression ptr_op ident { + if let Token::Identifier(name) = ident { + Expression::Arrow(expression::ExprArrow{ + src: Box::new(postfix_expression), + member: name, + }) + } else { + unreachable!() + } + } + | postfix_expression inc_op { + Expression::Unary(expression::ExprUnary { + op: expression::ExprUnaryOperator::IncrementPost, + src: Box::new(postfix_expression), + }) + } + | postfix_expression dec_op { + Expression::Unary(expression::ExprUnary{ + op: expression::ExprUnaryOperator::DecrementPost, + src: Box::new(postfix_expression), + }) + } + ; + + +argument_expression_list(Vec) + : assignment_expression { + vec![assignment_expression] + } + | argument_expression_list comma! assignment_expression { + argument_expression_list.push(assignment_expression); + argument_expression_list + } + ; + + +unary_expression(Expression) + : postfix_expression + | inc_op! unary_expression { + Expression::Unary( expression::ExprUnary{ + op: expression::ExprUnaryOperator::IncrementPre, + src: Box::new(unary_expression), + }) + } + | dec_op! unary_expression { + Expression::Unary( expression::ExprUnary{ + op: expression::ExprUnaryOperator::DecrementPre, + src: Box::new(unary_expression), + }) + } + | ampersand! cast_expression { + Expression::Unary( expression::ExprUnary{ + op: expression::ExprUnaryOperator::AddressOf, + src: Box::new(cast_expression), + }) + } + | star! cast_expression { + Expression::Unary( expression::ExprUnary{ + op: expression::ExprUnaryOperator::Dereference, + src: Box::new(cast_expression), + }) + } + | plus! cast_expression { + Expression::Unary( expression::ExprUnary{ + op: expression::ExprUnaryOperator::Plus, + src: Box::new(cast_expression), + }) + } + | minus! cast_expression { + Expression::Unary( expression::ExprUnary{ + op: expression::ExprUnaryOperator::Minus, + src: Box::new(cast_expression), + }) + } + | tilde! cast_expression { + Expression::Unary( expression::ExprUnary{ + op: expression::ExprUnaryOperator::BitwiseNot, + src: Box::new(cast_expression), + }) + } + | exclamation! cast_expression { + Expression::Unary( expression::ExprUnary{ + op: expression::ExprUnaryOperator::LogicalNot, + src: Box::new(cast_expression), + }) + } + | sizeof! unary_expression { + Expression::SizeofExpr(expression::ExprSizeOfExpr{ + expr: Box::new(unary_expression), + }) + } + | sizeof! lparen! type_name rparen! { + Expression::SizeofType( expression::ExprSizeOfType{ + typename: type_name, + }) + } + ; + +cast_expression(Expression) + : unary_expression + | lparen! type_name rparen! cast_expression { + Expression::Cast( expression::ExprCast{ + src: Box::new(cast_expression), + typename: type_name, + }) + } + ; + + +multiplicative_expression( Expression ) + : cast_expression + | multiplicative_expression star cast_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::Mul, + lhs: Box::new(multiplicative_expression), + rhs: Box::new(cast_expression), + }) + } + | multiplicative_expression slash cast_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::Div, + lhs: Box::new(multiplicative_expression), + rhs: Box::new(cast_expression), + }) + } + | multiplicative_expression percent cast_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::Mod, + lhs: Box::new(multiplicative_expression), + rhs: Box::new(cast_expression), + }) + } + ; + + +additive_expression( Expression ) + : multiplicative_expression + | additive_expression plus multiplicative_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::Add, + lhs: Box::new(additive_expression), + rhs: Box::new(multiplicative_expression), + }) + } + | additive_expression minus multiplicative_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::Sub, + lhs: Box::new(additive_expression), + rhs: Box::new(multiplicative_expression), + }) + } + ; + +shift_expression( Expression ) + : additive_expression + | shift_expression left_op additive_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::ShiftLeft, + lhs: Box::new(shift_expression), + rhs: Box::new(additive_expression), + }) + } + | shift_expression right_op additive_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::ShiftRight, + lhs: Box::new(shift_expression), + rhs: Box::new(additive_expression), + }) + } + ; + + +relational_expression(Expression) + : shift_expression + | relational_expression less shift_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::LessThan, + lhs: Box::new(relational_expression), + rhs: Box::new(shift_expression), + }) + } + | relational_expression greater shift_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::GreaterThan, + lhs: Box::new(relational_expression), + rhs: Box::new(shift_expression), + }) + } + | relational_expression le shift_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::LessThanOrEqual, + lhs: Box::new(relational_expression), + rhs: Box::new(shift_expression), + }) + } + | relational_expression ge shift_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::GreaterThanOrEqual, + lhs: Box::new(relational_expression), + rhs: Box::new(shift_expression), + }) + } + ; + + +equality_expression( Expression ) + : relational_expression + | equality_expression eq relational_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::Equal, + lhs: Box::new(equality_expression), + rhs: Box::new(relational_expression), + }) + } + | equality_expression ne relational_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::NotEqual, + lhs: Box::new(equality_expression), + rhs: Box::new(relational_expression), + }) + } + ; + + +and_expression( Expression ) + : equality_expression + | and_expression ampersand equality_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::BitwiseAnd, + lhs: Box::new(and_expression), + rhs: Box::new(equality_expression), + }) + } + ; + + +exclusive_or_expression ( Expression ) + : and_expression + | exclusive_or_expression caret and_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::BitwiseXor, + lhs: Box::new(exclusive_or_expression), + rhs: Box::new(and_expression), + }) + } + ; + +inclusive_or_expression( Expression ) + : exclusive_or_expression + | inclusive_or_expression pipe exclusive_or_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::BitwiseOr, + lhs: Box::new(inclusive_or_expression), + rhs: Box::new(exclusive_or_expression), + }) + } + ; + + +logical_and_expression( Expression ) + : inclusive_or_expression + | logical_and_expression and_op inclusive_or_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::LogicalAnd, + lhs: Box::new(logical_and_expression), + rhs: Box::new(inclusive_or_expression), + }) + } + ; + + +logical_or_expression( Expression ) + : logical_and_expression + | logical_or_expression or_op logical_and_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::LogicalOr, + lhs: Box::new(logical_or_expression), + rhs: Box::new(logical_and_expression), + }) + } + ; + +conditional_expression( Expression ) + : logical_or_expression + | logical_or_expression question expression colon conditional_expression { + Expression::Conditional( expression::ExprConditional{ + cond: Box::new(logical_or_expression), + then_expr: Box::new(expression), + else_expr: Box::new(conditional_expression), + }) + } + ; + +assignment_expression( Expression ) + : conditional_expression + | unary_expression mul_assign assignment_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::MulAssign, + lhs: Box::new(unary_expression), + rhs: Box::new(assignment_expression), + }) + } + | unary_expression div_assign assignment_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::DivAssign, + lhs: Box::new(unary_expression), + rhs: Box::new(assignment_expression), + }) + } + | unary_expression mod_assign assignment_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::ModAssign, + lhs: Box::new(unary_expression), + rhs: Box::new(assignment_expression), + }) + } + | unary_expression add_assign assignment_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::AddAssign, + lhs: Box::new(unary_expression), + rhs: Box::new(assignment_expression), + }) + } + | unary_expression sub_assign assignment_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::SubAssign, + lhs: Box::new(unary_expression), + rhs: Box::new(assignment_expression), + }) + } + | unary_expression left_assign assignment_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::ShiftLeftAssign, + lhs: Box::new(unary_expression), + rhs: Box::new(assignment_expression), + }) + } + | unary_expression right_assign assignment_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::ShiftRightAssign, + lhs: Box::new(unary_expression), + rhs: Box::new(assignment_expression), + }) + } + | unary_expression and_assign assignment_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::BitwiseAndAssign, + lhs: Box::new(unary_expression), + rhs: Box::new(assignment_expression), + }) + } + | unary_expression xor_assign assignment_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::BitwiseXorAssign, + lhs: Box::new(unary_expression), + rhs: Box::new(assignment_expression), + }) + } + | unary_expression or_assign assignment_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::BitwiseOrAssign, + lhs: Box::new(unary_expression), + rhs: Box::new(assignment_expression), + }) + } + ; + +expression( Expression ) + : assignment_expression + | expression comma assignment_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::Comma, + lhs: Box::new(expression), + rhs: Box::new(assignment_expression), + }) + } + ; + +constant_expression( Expression ) + : conditional_expression + ; + + + +initializer( Expression ) + : assignment_expression + | lbrace! initializer_list rbrace! { + Expression::InitializerList( expression::ExprInitializerList{ + initializers: initializer_list, + }) + } + | lbrace! initializer_list comma! rbrace! { + Expression::InitializerList( expression::ExprInitializerList{ + initializers: initializer_list, + }) + } + ; + +initializer_list( Vec ) + : initializer { + vec![initializer] + } + | initializer_list comma! initializer { + initializer_list.push(initializer); + initializer_list + } + ; + + +labeled_statement ( Statement ) + : ident colon statement { + if let Token::Identifier(label) = ident { + Statement::Labeled( statement::StmtLabeled{ + label, + statement: Box::new(statement), + }) + } else { + unreachable!() + } + } + | case constant_expression colon statement { + Statement::Case( statement::StmtCase{ + value: constant_expression, + statement: Box::new(statement), + }) + } + | default colon statement { + Statement::Default( statement::StmtDefault{ + statement: Box::new(statement), + }) + } + ; + +statement_or_declaration( Statement ) + : statement + | declaration + ; + +compound_statement( Statement ) + : lbrace! statement_or_declaration* rbrace! { + Statement::Compound( statement::StmtCompound{ + statements: statement_or_declaration + }) + } + ; + + +expression_statement( Statement ) + : semicolon { + Statement::Null( statement::StmtNull{} ) + } + | expression semicolon { + Statement::Expression( statement::StmtExpression{ + expression: expression, + }) + } + ; + + +selection_statement( Statement ) + : if_ lparen! expression rparen! statement { + Statement::If( statement::StmtIf{ + cond: expression, + then_statement: Box::new(statement), + else_statement: None, + }) + } + | if_ lparen expression rparen thenstmt=statement else_ elsestmt=statement { + Statement::If( statement::StmtIf{ + cond: expression, + then_statement: Box::new(thenstmt), + else_statement: Some(Box::new(elsestmt)), + }) + } + | switch lparen expression rparen statement { + Statement::Switch( statement::StmtSwitch{ + target: expression, + statement: Box::new(statement), + }) + } + ; + + +iteration_statement( Statement ) + : while_ lparen expression rparen statement { + Statement::While( statement::StmtWhile{ + cond: expression, + statement: Box::new(statement), + }) + } + | do_ statement while_ lparen expression rparen semicolon { + Statement::DoWhile( statement::StmtDoWhile{ + cond: expression, + statement: Box::new(statement), + }) + } + | for_ lparen init=expression_statement cond=expression_statement rparen body=statement { + let Statement::Expression(init) = init else { unreachable!() }; + let Statement::Expression(cond) = cond else { unreachable!() }; + Statement::For( statement::StmtFor{ + init: init.expression, + cond: cond.expression, + next: None, + statement: Box::new(body), + }) + } + | for_ lparen init=expression_statement cond=expression_statement next=expression rparen body=statement { + let Statement::Expression(init) = init else { unreachable!() }; + let Statement::Expression(cond) = cond else { unreachable!() }; + Statement::For( statement::StmtFor{ + init: init.expression, + cond: cond.expression, + next: Some(next), + statement: Box::new(body), + }) + } + ; + + +jump_statement( Statement ) + : goto_ ident semicolon { + let Token::Identifier(ident) = ident else { unreachable!() }; + Statement::Goto( statement::StmtGoto{ + label: ident, + }) + } + | continue_ semicolon { + Statement::Continue( statement::StmtContinue{} ) + } + | break_ semicolon { + Statement::Break( statement::StmtBreak{} ) + } + | return_ semicolon { + Statement::Return( statement::StmtReturn{ + expr: None, + }) + } + | return_ expression semicolon { + Statement::Return( statement::StmtReturn{ + expr: Some(expression), + }) + } + ; + +declaration( Statement ) + : declaration_specifier+ semicolon { + Statement::Declaration( statement::StmtDeclaration{ + specs: declaration_specifier, + inits: None, + }) + } + | declaration_specifier+ inits=init_declarator_list semicolon { + Statement::Declaration( statement::StmtDeclaration{ + specs: declaration_specifier, + inits: Some(inits), + }) + } + ; + +// what is declaration_list for? in function definition? +function_definition( Statement ) + // : declaration_specifier+ declarator declaration+ compound_statement + : declaration_specifier+ declarator compound_statement { + Statement::FunctionDefinition( statement::StmtFunctionDefinition{ + specs: Some(declaration_specifier), + decl: declarator, + body: Box::new(compound_statement), + }) + } + // | declarator declaration+ compound_statement + | declarator compound_statement { + Statement::FunctionDefinition( statement::StmtFunctionDefinition { + specs: None, + decl: declarator, + body: Box::new(compound_statement), + }) + } + ; + +statement( Statement ) + : labeled_statement + | compound_statement + | expression_statement + | selection_statement + | iteration_statement + | jump_statement + ; + +external_declaration( Statement ) + : function_definition + | declaration + ; + +translation_unit( statement::TranslationUnit ) + : external_declaration* { + statement::TranslationUnit { + statements: external_declaration + } + } + ; + +type_qualifier( declarator::TypeQualifier ) + : const_ { declarator::TypeQualifier::Const } + | volatile { declarator::TypeQualifier::Volatile } + ; + +declarator( Declarator ) + : direct_declarator + | star! type_qualifier* declarator { + while let Some(type_qual) = type_qualifier.pop() { + match type_qual { + declarator::TypeQualifier::Const => { + declarator = Declarator::Const(declarator::DeclConst{ + declarator: Some(Box::new(declarator)), + }); + } + declarator::TypeQualifier::Volatile => { + declarator = Declarator::Volatile(declarator::DeclVolatile{ + declarator: Some(Box::new(declarator)), + }); + } + } + } + declarator = Declarator::Pointer(declarator::DeclPointer{ + declarator: Some(Box::new(declarator)), + }); + declarator + } + ; + +direct_declarator( Declarator ) + : ident { + let Token::Identifier(name) = ident else { unreachable!() }; + Declarator::Identifier(declarator::DeclIdentifier{ name }) + } + | lparen! declarator rparen! + | direct_declarator lbracket! constant_expression rbracket! { + Declarator::ArrayFixed(declarator::DeclArrayFixed{ + declarator: Some(Box::new(direct_declarator)), + size: constant_expression, + }) + } + | direct_declarator lbracket! rbracket! { + Declarator::ArrayUnbounded(declarator::DeclArrayUnbounded{ + declarator: Some(Box::new(direct_declarator)), + }) + } + | direct_declarator lparen! parameter_type_list rparen! { + Declarator::Function(declarator::DeclFunction{ + declarator: Some(Box::new(direct_declarator)), + params: parameter_type_list, + }) + } + | direct_declarator lparen! rparen! { + Declarator::Function(declarator::DeclFunction{ + declarator: Some(Box::new(direct_declarator)), + params: declarator::ParameterList { + params: Vec::new(), + variadic: false + } + }) + } + ; + + +abstract_declarator(Declarator) + : star! type_qualifier* abstract_declarator { + let mut declarator = abstract_declarator; + while let Some(type_qual) = type_qualifier.pop() { + match type_qual { + declarator::TypeQualifier::Const => { + declarator = Declarator::Const(declarator::DeclConst{ + declarator: Some(Box::new(declarator)), + }); + } + declarator::TypeQualifier::Volatile => { + declarator = Declarator::Volatile(declarator::DeclVolatile{ + declarator: Some(Box::new(declarator)), + }); + } + } + } + declarator = Declarator::Pointer(declarator::DeclPointer{ + declarator: Some(Box::new(declarator)), + }); + declarator + } + | star! type_qualifier* { + let mut declarator = None; + while let Some(type_qual) = type_qualifier.pop() { + match type_qual { + declarator::TypeQualifier::Const => { + declarator = Some(Declarator::Const(declarator::DeclConst{ + declarator: declarator.map( Box::new ), + })); + } + declarator::TypeQualifier::Volatile => { + declarator = Some(Declarator::Volatile(declarator::DeclVolatile{ + declarator: declarator.map( Box::new ), + })); + } + } + } + Declarator::Pointer(declarator::DeclPointer{ + declarator: declarator.map( Box::new ), + }) + } + | direct_abstract_declarator + ; + +direct_abstract_declarator( Declarator ) + : lparen! abstract_declarator rparen! + | lbracket! rbracket! { + Declarator::ArrayUnbounded(declarator::DeclArrayUnbounded{ + declarator: None, + }) + } + | lbracket! constant_expression rbracket! { + Declarator::ArrayFixed(declarator::DeclArrayFixed{ + declarator: None, + size: constant_expression, + }) + } + | direct_abstract_declarator lbracket! rbracket! { + Declarator::ArrayUnbounded(declarator::DeclArrayUnbounded{ + declarator: Some(Box::new(direct_abstract_declarator)), + }) + } + | direct_abstract_declarator lbracket! constant_expression rbracket! { + Declarator::ArrayFixed(declarator::DeclArrayFixed{ + declarator: Some(Box::new(direct_abstract_declarator)), + size: constant_expression, + }) + } + | lparen! rparen! { + Declarator::Function(declarator::DeclFunction{ + declarator: None, + params: declarator::ParameterList { + params: Vec::new(), + variadic: false + } + }) + } + | lparen! parameter_type_list rparen! { + Declarator::Function(declarator::DeclFunction{ + declarator: None, + params: parameter_type_list, + }) + } + | direct_abstract_declarator lparen! rparen! { + Declarator::Function(declarator::DeclFunction{ + declarator: Some(Box::new(direct_abstract_declarator)), + params: declarator::ParameterList { + params: Vec::new(), + variadic: false, + } + }) + } + | direct_abstract_declarator lparen! parameter_type_list rparen! { + Declarator::Function(declarator::DeclFunction{ + declarator: Some(Box::new(direct_abstract_declarator)), + params: parameter_type_list, + }) + } + ; + +specifier_qualifier( declarator::SpecifierQualifier ) + : type_qualifier { + declarator::SpecifierQualifier::TypeQualifier(type_qualifier) + } + | type_specifier { + declarator::SpecifierQualifier::TypeSpecifier(type_specifier) + } + ; + +type_name( declarator::Typename ) + : specifier_qualifier+ abstract_declarator? { + declarator::Typename { + specs: specifier_qualifier, + declarator: abstract_declarator.map(Box::new), + } + } + ; + +type_specifier( declarator::TypeSpecifier ) + : void_ { + declarator::TypeSpecifier::Void + } + | char_ { + declarator::TypeSpecifier::Char + } + | short_ { + declarator::TypeSpecifier::Short + } + | int_ { + declarator::TypeSpecifier::Int + } + | long_ { + declarator::TypeSpecifier::Long + } + | float_ { + declarator::TypeSpecifier::Float + } + | double_ { + declarator::TypeSpecifier::Double + } + | signed { + declarator::TypeSpecifier::Signed + } + | unsigned { + declarator::TypeSpecifier::Unsigned + } + // | ident { + // let Token::Identifier(ident) = ident else { unreachable!() }; + // declarator::TypeSpecifier::Typename(ident) + // } + | struct_or_union_specifier { + declarator::TypeSpecifier::StructOrUnion(struct_or_union_specifier) + } + | enum_specifier { + declarator::TypeSpecifier::Enum(enum_specifier) + } + ; + +storage_class_specifier( declarator::StorageClassSpecifier ) + : typedef { + declarator::StorageClassSpecifier::Typedef + } + | extern_ { + declarator::StorageClassSpecifier::Extern + } + | static_ { + declarator::StorageClassSpecifier::Static + } + | auto { + declarator::StorageClassSpecifier::Auto + } + | register { + declarator::StorageClassSpecifier::Register + } + ; +declaration_specifier( declarator::DeclarationSpecifier ) + : storage_class_specifier { + declarator::DeclarationSpecifier::StorageClassSpecifier(storage_class_specifier) + } + | type_specifier { + declarator::DeclarationSpecifier::TypeSpecifier(type_specifier) + } + | type_qualifier { + declarator::DeclarationSpecifier::TypeQualifier(type_qualifier) + } + ; + +parameter_declaration( declarator::ParameterDeclaration ) + : declaration_specifier+ declarator { + declarator::ParameterDeclaration{ + specs: declaration_specifier, + declarator: Some(Box::new(declarator)), + } + } + | declaration_specifier+ abstract_declarator { + declarator::ParameterDeclaration{ + specs: declaration_specifier, + declarator: Some(Box::new(abstract_declarator)), + } + } + | declaration_specifier+ { + declarator::ParameterDeclaration{ + specs: declaration_specifier, + declarator: None, + } + } + ; + +parameter_list( Vec ) + : parameter_declaration { + vec![parameter_declaration] + } + | parameter_list comma! parameter_declaration { + parameter_list.push(parameter_declaration); + parameter_list + } + ; + +parameter_type_list( declarator::ParameterList ) + : parameter_list { + declarator::ParameterList { + params: parameter_list, + variadic: false, + } + } + | parameter_list comma! ellipsis { + declarator::ParameterList{ + params: parameter_list, + variadic: true, + } + } + ; + +// returns is_struct +struct_or_union( bool ) + : struct_ { + true + } + | union_ { + false + } + ; + +struct_declarator( Declarator ) + : declarator + // @TODO + // bit field + ; + +struct_declarator_list( Vec ) + : struct_declarator { + vec![struct_declarator] + } + | struct_declarator_list comma! struct_declarator { + struct_declarator_list.push(struct_declarator); + struct_declarator_list + } + ; + +struct_declaration( declarator::StructDeclaration ) + : specifier_qualifier+ struct_declarator_list { + declarator::StructDeclaration { + specs: specifier_qualifier, + declarators: struct_declarator_list, + } + } + ; + +struct_or_union_specifier( declarator::StructOrUnionSpecifier ) + : struct_or_union ident? lbrace! struct_declaration* rbrace! { + let name = ident.map(|name| { let Token::Identifier(name) = name else { unreachable!() }; name }); + declarator::StructOrUnionSpecifier { + is_struct: struct_or_union, + name, + decls: Some(struct_declaration), + } + } + | struct_or_union ident { + let Token::Identifier(name) = ident else { unreachable!() }; + declarator::StructOrUnionSpecifier { + is_struct: struct_or_union, + name: Some(name), + decls: None, + } + } + ; + +enum_specifier( declarator::EnumSpecifier ) + : enum_! ident? lbrace! enumerator_list rbrace! { + let name = ident.map(|name| { let Token::Identifier(name) = name else { unreachable!() }; name }); + declarator::EnumSpecifier { + name, + enumerators: Some(enumerator_list), + } + } + | enum_! ident { + let Token::Identifier(name) = ident else { unreachable!() }; + declarator::EnumSpecifier { + name: Some(name), + enumerators: None, + } + } + ; + +enumerator_list( Vec ) + : enumerator { + vec![enumerator] + } + | enumerator_list comma! enumerator { + enumerator_list.push(enumerator); + enumerator_list + } + ; + +enumerator( declarator::Enumerator ) + : ident { + let Token::Identifier(name) = ident else { unreachable!() }; + declarator::Enumerator { + name, + value: None, + } + } + | ident eq constant_expression { + let Token::Identifier(name) = ident else { unreachable!() }; + declarator::Enumerator { + name, + value: Some(constant_expression), + } + } + ; + + +init_declarator( declarator::DeclInit ) + : declarator { + declarator::DeclInit{ + declarator: Box::new(declarator), + initializer: None, + } + } + | declarator eq initializer { + declarator::DeclInit{ + declarator: Box::new(declarator), + initializer: Some(initializer) + } + } + ; + +init_declarator_list( Vec ) + : init_declarator { + vec![init_declarator] + } + | init_declarator_list comma! init_declarator { + init_declarator_list.push(init_declarator); + init_declarator_list + } + ; + +} diff --git a/src/ast/statement.rs b/src/ast/statement.rs index 9f71821..179a0b2 100644 --- a/src/ast/statement.rs +++ b/src/ast/statement.rs @@ -1,12 +1,5 @@ -use super::{expression::Expression, typename::TypeInfo}; -use crate::virtualmachine::instruction::generation::FunctionInfo; -use crate::virtualmachine::instruction::generation::InstructionGenerator; -use crate::virtualmachine::instruction::operand::Operand; -use crate::virtualmachine::instruction::*; -use crate::virtualmachine::program::STACK_POINTER_BASE_REGISTER; -use crate::virtualmachine::program::STACK_POINTER_REGISTER; -use crate::virtualmachine::scope::FunctionScope; -use crate::virtualmachine::variable::VariableData; +use super::declarator; +use super::expression::Expression; #[derive(Debug, Clone)] pub enum Statement { @@ -25,59 +18,21 @@ pub enum Statement { For(StmtFor), Goto(StmtGoto), Return(StmtReturn), - StructDefinition(StmtStructDefinition), - FunctionDeclaration(StmtFunctionDeclaration), Declaration(StmtDeclaration), - Typedef(StmtTypedef), FunctionDefinition(StmtFunctionDefinition), - TranslationUnit(TranslationUnit), -} - -impl Statement { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - match self { - Statement::Null(stmt) => stmt.emit(instructions), - Statement::Expression(stmt) => stmt.emit(instructions), - Statement::Labeled(stmt) => stmt.emit(instructions), - Statement::Compound(stmt) => stmt.emit(instructions), - Statement::If(stmt) => stmt.emit(instructions), - Statement::Switch(stmt) => stmt.emit(instructions), - Statement::Case(stmt) => stmt.emit(instructions), - Statement::Default(stmt) => stmt.emit(instructions), - Statement::Continue(stmt) => stmt.emit(instructions), - Statement::Break(stmt) => stmt.emit(instructions), - Statement::While(stmt) => stmt.emit(instructions), - Statement::DoWhile(stmt) => stmt.emit(instructions), - Statement::For(stmt) => stmt.emit(instructions), - Statement::Goto(stmt) => stmt.emit(instructions), - Statement::Return(stmt) => stmt.emit(instructions), - Statement::StructDefinition(stmt) => stmt.emit(instructions), - Statement::FunctionDeclaration(stmt) => stmt.emit(instructions), - Statement::Declaration(stmt) => stmt.emit(instructions), - Statement::Typedef(stmt) => stmt.emit(instructions), - Statement::FunctionDefinition(stmt) => stmt.emit(instructions), - Statement::TranslationUnit(stmt) => stmt.emit(instructions), - } - } } /// Statements that do nothing #[derive(Debug, Clone)] pub struct StmtNull; -impl StmtNull { - pub fn emit(&self, _instructions: &mut InstructionGenerator) {} -} +impl StmtNull {} /// for any expression ends with semicolon ';' #[derive(Debug, Clone)] pub struct StmtExpression { pub expression: Expression, } -impl StmtExpression { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - self.expression.emit(instructions); - } -} +impl StmtExpression {} /// label: /// statement @@ -86,29 +41,14 @@ pub struct StmtLabeled { pub label: String, pub statement: Box, } -impl StmtLabeled { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - instructions.set_label(&self.label); - self.statement.emit(instructions); - } -} +impl StmtLabeled {} /// { statements ... } #[derive(Debug, Clone)] pub struct StmtCompound { pub statements: Vec, } -impl StmtCompound { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - instructions.push_scope(); - - for statement in &self.statements { - statement.emit(instructions); - } - - instructions.pop_scope(); - } -} +impl StmtCompound {} /// if ( condition_expression ) then_statement else else_statement /// no else if statement @@ -118,27 +58,7 @@ pub struct StmtIf { pub then_statement: Box, pub else_statement: Option>, } -impl StmtIf { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - let else_label = instructions.get_unique_label(); - let end_label = instructions.get_unique_label(); - - self.cond.emit(instructions); - instructions.push(Instruction::JumpZero(JumpZero { - label: else_label.clone(), - operand_cond: Operand::Register(0), - })); - self.then_statement.emit(instructions); - instructions.push(Instruction::Jump(Jump { - label: end_label.clone(), - })); - instructions.set_label(&else_label); - if let Some(else_statement) = &self.else_statement { - else_statement.emit(instructions); - } - instructions.set_label(&end_label); - } -} +impl StmtIf {} /// switch ( target_expression ) body_statement #[derive(Debug, Clone)] @@ -146,183 +66,31 @@ pub struct StmtSwitch { pub target: Expression, pub statement: Box, } -impl StmtSwitch { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - let end_label = instructions.get_unique_label(); - let default_label = instructions.get_unique_label(); - instructions - .label_stack - .push((default_label.clone(), end_label.clone())); - - // push target to stack - self.target.emit(instructions); - if self.target.is_return_reference(instructions) { - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Derefed(0, 0), - })); - } else { - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Register(0), - })); - } - // and push variable for 'if the pattern matched already?' - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Value(VariableData::UInt8(0)), - })); - - // body - self.statement.emit(instructions); - // check if the pattern matched and default is defined - if instructions.labels.get(&default_label).is_some() { - // if not matched, set pattern matched to true and goto default - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(STACK_POINTER_REGISTER, -1), - operand_to: Operand::Register(0), - })); - instructions.push(Instruction::JumpZero(JumpZero { - label: default_label.clone(), - operand_cond: Operand::Register(0), - })); - } - - // end label here, cleanup - instructions.set_label(&end_label); - // pop pattern-matched state and target from stack - instructions.push(Instruction::SubAssign(SubAssign { - lhs: Operand::Register(STACK_POINTER_REGISTER), - rhs: Operand::Value(VariableData::UInt64(2)), - })); - - instructions - .label_stack - .pop() - .expect("Switch: label_stack is empty"); - } -} +impl StmtSwitch {} /// case value: statement #[derive(Debug, Clone)] pub struct StmtCase { pub value: Expression, pub statement: Box, } -impl StmtCase { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - let case_end_label = instructions.get_unique_label(); - let comparison_skip_label = instructions.get_unique_label(); - - // copy state from stack - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(STACK_POINTER_REGISTER, -1), - operand_to: Operand::Register(0), - })); - // if the pattern matched already, skip comparison - instructions.push(Instruction::JumpNonZero(JumpNonZero { - label: comparison_skip_label.clone(), - operand_cond: Operand::Register(0), - })); - - // comparison start here - // evaluate value - self.value.emit(instructions); - // register1 = value - if self.value.is_return_reference(instructions) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(0, 0), - operand_to: Operand::Register(1), - })); - } else { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Register(0), - operand_to: Operand::Register(1), - })); - } - // register0 = target - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(STACK_POINTER_REGISTER, -2), - operand_to: Operand::Register(0), - })); - // register2 = result of comparison - instructions.push(Instruction::Equal(Equal { - lhs: Operand::Register(0), - rhs: Operand::Register(1), - to: Operand::Register(2), - })); - instructions.push(Instruction::JumpZero(JumpZero { - label: case_end_label.clone(), - operand_cond: Operand::Register(2), - })); - - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Value(VariableData::UInt8(1)), - operand_to: Operand::Derefed(STACK_POINTER_REGISTER, -1), - })); - - instructions.set_label(&comparison_skip_label); - self.statement.emit(instructions); - - instructions.set_label(&case_end_label); - } -} +impl StmtCase {} /// default: statement #[derive(Debug, Clone)] pub struct StmtDefault { pub statement: Box, } -impl StmtDefault { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - let default_end_label = instructions.get_unique_label(); - let (default_label, _) = instructions - .label_stack - .last() - .expect("Default: label_stack is empty") - .clone(); - // skip default statement - instructions.push(Instruction::Jump(Jump { - label: default_end_label.clone(), - })); - instructions.set_label(&default_label); - // set pattern matched - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Value(VariableData::UInt8(1)), - operand_to: Operand::Derefed(STACK_POINTER_REGISTER, -1), - })); - self.statement.emit(instructions); - instructions.set_label(&default_end_label); - } -} +impl StmtDefault {} /// continue; #[derive(Debug, Clone)] pub struct StmtContinue; -impl StmtContinue { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - let continue_label = &instructions - .label_stack - .last() - .expect("Continue: label_stack is empty") - .0; - instructions.push(Instruction::Jump(Jump { - label: continue_label.clone(), - })); - } -} +impl StmtContinue {} /// break; #[derive(Debug, Clone)] pub struct StmtBreak; -impl StmtBreak { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - let end_label = &instructions - .label_stack - .last() - .expect("Break: label_stack is empty") - .1; - instructions.push(Instruction::Jump(Jump { - label: end_label.clone(), - })); - } -} +impl StmtBreak {} /// while ( condition_expression ) statement #[derive(Debug, Clone)] @@ -330,39 +98,7 @@ pub struct StmtWhile { pub cond: Expression, pub statement: Box, } -impl StmtWhile { - fn emit(&self, instructions: &mut InstructionGenerator) { - let start_label = instructions.get_unique_label(); - let end_label = instructions.get_unique_label(); - instructions - .label_stack - .push((start_label.clone(), end_label.clone())); - - instructions.set_label(&start_label); - self.cond.emit(instructions); - if self.cond.is_return_reference(instructions) { - instructions.push(Instruction::JumpZero(JumpZero { - label: end_label.clone(), - operand_cond: Operand::Derefed(0, 0), - })); - } else { - instructions.push(Instruction::JumpZero(JumpZero { - label: end_label.clone(), - operand_cond: Operand::Register(0), - })); - } - self.statement.emit(instructions); - instructions.push(Instruction::Jump(Jump { - label: start_label.clone(), - })); - instructions.set_label(&end_label); - - instructions - .label_stack - .pop() - .expect("While: label_stack is empty"); - } -} +impl StmtWhile {} /// do statement while ( condition_expression ); @@ -371,46 +107,6 @@ pub struct StmtDoWhile { pub cond: Expression, pub statement: Box, } -impl StmtDoWhile { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - let start_label = instructions.get_unique_label(); - let continue_label = instructions.get_unique_label(); - let end_label = instructions.get_unique_label(); - - instructions - .label_stack - .push((continue_label.clone(), end_label.clone())); - - // start_label: - // do { body ... } - // continue_label: - // while (cond); - // end_label: - - instructions.set_label(&start_label); - self.statement.emit(instructions); - - instructions.set_label(&continue_label); - self.cond.emit(instructions); - if self.cond.is_return_reference(instructions) { - instructions.push(Instruction::JumpNonZero(JumpNonZero { - label: start_label.clone(), - operand_cond: Operand::Derefed(0, 0), - })); - } else { - instructions.push(Instruction::JumpNonZero(JumpNonZero { - label: start_label.clone(), - operand_cond: Operand::Register(0), - })); - } - instructions.set_label(&end_label); - - instructions - .label_stack - .pop() - .expect("DoWhile: label_stack is empty"); - } -} /// for ( init; cond; next ) statement /// since init is expression, must declare variable before entering for loop @@ -421,484 +117,33 @@ pub struct StmtFor { pub next: Option, pub statement: Box, } -impl StmtFor { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - let cond_label = instructions.get_unique_label(); - let end_label = instructions.get_unique_label(); - let continue_label = instructions.get_unique_label(); - instructions - .label_stack - .push((continue_label.clone(), end_label.clone())); - - // init - // COND: - // cond - // body - // CONTINUE: - // next - // jump COND - // END: - - self.init.emit(instructions); - instructions.set_label(&cond_label); - self.cond.emit(instructions); - if self.cond.is_return_reference(instructions) { - instructions.push(Instruction::JumpZero(JumpZero { - label: end_label.clone(), - operand_cond: Operand::Derefed(0, 0), - })); - } else { - instructions.push(Instruction::JumpZero(JumpZero { - label: end_label.clone(), - operand_cond: Operand::Register(0), - })); - } - self.statement.emit(instructions); - instructions.set_label(&continue_label); - if let Some(next) = &self.next { - next.emit(instructions); - } - instructions.push(Instruction::Jump(Jump { - label: cond_label.clone(), - })); - instructions.set_label(&end_label); - - instructions - .label_stack - .pop() - .expect("For: label_stack is empty"); - } -} /// goto label; #[derive(Debug, Clone)] pub struct StmtGoto { pub label: String, } -impl StmtGoto { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - instructions.push(Instruction::Jump(Jump { - label: self.label.clone(), - })); - } -} /// return; or return expression; #[derive(Debug, Clone)] pub struct StmtReturn { pub expr: Option, } -impl StmtReturn { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - if let Some(expr) = &self.expr { - expr.emit(instructions); - // force return as value - if expr.is_return_reference(instructions) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(0, 0), - operand_to: Operand::Register(0), - })); - } - } - instructions.push(Instruction::Return(Return {})); - } -} -/// type definition of struct, union, enum -#[derive(Debug, Clone)] -pub struct StmtStructDefinition { - pub typeinfo: TypeInfo, -} -impl StmtStructDefinition { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - match &self.typeinfo { - TypeInfo::Struct(t) => { - if t.name.is_none() { - println!("Anonymous struct in declaration statement; ignored it"); - } else { - let old = if instructions.scopes.is_empty() { - &mut instructions.global_scope - } else { - instructions.scopes.last_mut().unwrap() - } - .type_infos - .insert( - t.name.as_ref().unwrap().clone(), - TypeInfo::Struct(t.clone()), - ); - if old.is_some() { - panic!("Struct {} already exists", t.name.as_ref().unwrap()); - } - } - } - _ => panic!("Invalid type for type declaration: {:?}", self.typeinfo), - } - } -} - -/// return_type function_name ( params ); -#[derive(Debug, Clone)] -pub struct StmtFunctionDeclaration { - pub return_type: TypeInfo, - pub name: String, - pub params: Vec, -} -impl StmtFunctionDeclaration { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - // check if its already declared - let old = instructions.functions.get(&self.name); - if let Some(old) = old { - // no need to check if the function is already defined, - // since this statement is declaration statement - - // check parameter types are same - let param_equal = old - .params - .iter() - .map(|(_, type_)| type_) - .eq(self.params.iter()); - if param_equal == false { - panic!( - "Function {} is already declared with different parameter types", - &self.name - ); - } - - // check return type is same - if &old.return_type != &self.return_type { - panic!( - "Function {} is already declared with different return type", - &self.name - ); - } - } else { - // function is not declared - let params: Vec<_> = self - .params - .iter() - .map(|typeinfo| (None, typeinfo.clone())) - .collect(); - let function_data = FunctionInfo { - return_type: self.return_type.clone(), - params, - is_defined: false, - }; - instructions - .functions - .insert(self.name.clone(), function_data); - } - } -} - -/// typename var1, var2, var3, ...,; -/// var_i can be decorated with qualifiers; pointer, const ... #[derive(Debug, Clone)] pub struct StmtDeclaration { - pub vars: Vec<(String, TypeInfo, Option)>, // name, type, initializer -} -impl StmtDeclaration { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - for declaration in &self.vars { - // variable declaration - if let Some(initial_value) = &declaration.2 { - // variable with initial value - - let var_type = instructions.get_true_typeinfo(&declaration.1); - // check type - match var_type.remove_const() { - TypeInfo::Function(_, _) => { - panic!( - "Function declaration cannot have initial value; something went wrong" - ); - } - TypeInfo::Struct(sinfo) => { - // link name to stack - instructions.declare_variable( - &declaration.0, - &var_type, - sinfo.number_of_primitives(), - ); - - sinfo.emit_init(instructions, initial_value); - } - TypeInfo::Union(_uinfo) => { - panic!("Union declaration in declaration statement is not implemented"); - } - - // array - TypeInfo::Array(type_, size) => { - // initializer must be initializer list - let initial_value = match initial_value { - Expression::InitializerList(initial_value) => initial_value, - _ => unreachable!("Array initializer must be initializer list"), - }; - - let size = match size { - Some(size) => { - if initial_value.initializers.len() > size { - panic!("Too many initializers for array"); - } - size - } - None => initial_value.initializers.len(), - }; - if size == 0 { - panic!("Array size must be greater than 0"); - } - - // link name to stack - instructions.declare_variable( - &declaration.0, - &TypeInfo::Array(type_.clone(), Some(size)), - size * type_.number_of_primitives(), - ); - - TypeInfo::Array(type_.clone(), Some(size)) - .emit_init(instructions, declaration.2.as_ref().unwrap()); - } - - // primitive types + pointer - TypeInfo::UInt8 - | TypeInfo::UInt16 - | TypeInfo::UInt32 - | TypeInfo::UInt64 - | TypeInfo::Int8 - | TypeInfo::Int16 - | TypeInfo::Int32 - | TypeInfo::Int64 - | TypeInfo::Float32 - | TypeInfo::Float64 - | TypeInfo::Pointer(_) => { - // link name to stack - instructions.declare_variable(&declaration.0, &var_type, 1); - - var_type.emit_init(instructions, initial_value); - } - _ => panic!( - "Invalid type for variable declaration: {:?}", - &declaration.1 - ), - } - } else { - // variable without initial value - - let var_type = instructions.get_true_typeinfo(&declaration.1); - match var_type.remove_const() { - TypeInfo::Struct(sinfo) => { - let size = sinfo.number_of_primitives(); - if size == 0 { - panic!("Struct size must be greater than 0"); - } - // link name to stack - instructions.declare_variable(&declaration.0, &var_type, size); - - sinfo.emit_default(instructions); - } - TypeInfo::Union(_uinfo) => { - panic!("Union declaration in declaration statement is not implemented"); - } - - TypeInfo::Array(type_, size) => { - let size = - size.expect("Array declaration without initializer must have size"); - if size == 0 { - panic!("Array size must be greater than 0"); - } - - // link name to stack - instructions.declare_variable( - &declaration.0, - &TypeInfo::Array(type_.clone(), Some(size)), - size * type_.number_of_primitives(), - ); - - TypeInfo::Array(type_.clone(), Some(size)).emit_default(instructions); - } - - // primitive types + pointer - TypeInfo::UInt8 - | TypeInfo::UInt16 - | TypeInfo::UInt32 - | TypeInfo::UInt64 - | TypeInfo::Int8 - | TypeInfo::Int16 - | TypeInfo::Int32 - | TypeInfo::Int64 - | TypeInfo::Float32 - | TypeInfo::Float64 - | TypeInfo::Pointer(_) => { - // link name to stack - instructions.declare_variable(&declaration.0, &var_type, 1); - - // push default value to stack - var_type.emit_default(instructions); - } - _ => panic!( - "Invalid type for variable declaration: {:?}", - &declaration.1 - ), - } - } - } - } -} - -#[derive(Debug, Clone)] -pub struct StmtTypedef { - pub name: String, - pub typeinfo: TypeInfo, -} -impl StmtTypedef { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - let old = if instructions.scopes.is_empty() { - &mut instructions.global_scope - } else { - instructions.scopes.last_mut().unwrap() - } - .type_infos - .insert(self.name.clone(), self.typeinfo.clone()); - if old.is_some() { - panic!("Type {} already exists", self.name); - } - } + pub specs: Vec, + pub inits: Option>, } #[derive(Debug, Clone)] pub struct StmtFunctionDefinition { - pub return_type: TypeInfo, - pub name: String, - pub params: Vec<(Option, TypeInfo)>, + pub specs: Option>, + pub decl: declarator::Declarator, pub body: Box, } -impl StmtFunctionDefinition { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - if instructions.function_scope.is_some() { - panic!("nested function is not allowed"); - } - - let function_data = FunctionInfo { - return_type: instructions.get_true_typeinfo(&self.return_type), - params: self - .params - .iter() - .map(|(name, type_)| (name.clone(), instructions.get_true_typeinfo(type_))) - .collect(), - is_defined: true, - }; - let old = instructions - .functions - .insert(self.name.clone(), function_data); - if let Some(old) = old { - // check if old was declaration - if old.is_defined { - panic!("redefinition of function {}", &self.name); - } - - // check parameter types are same - if old - .params - .iter() - .map(|(_, type_)| instructions.get_true_typeinfo(type_)) - .eq(self - .params - .iter() - .map(|(_, type_)| instructions.get_true_typeinfo(type_))) - == false - { - panic!( - "Function {} is already declared with different parameter types", - &self.name - ); - } - - // check return type is same - if instructions.get_true_typeinfo(&old.return_type) - != instructions.get_true_typeinfo(&self.return_type) - { - panic!( - "Function {} is already declared with different return type", - &self.name - ); - } - } - instructions.set_label(&self.name); - - instructions.function_scope = Some(FunctionScope::new()); - instructions.push_scope(); - - // argument initialization - // function's arguments are pushed to stack before call ( and MUST BE ) - // ===== top of stack: return_address -> arg1 -> arg2 ... ===== - // ^ top of stack - - for (id, param) in self.params.iter().enumerate() { - if param.0.is_some() { - instructions.link_variable( - param.0.as_ref().unwrap(), - &instructions.get_true_typeinfo(¶m.1), - -(id as isize) - 3, - ); - } - } - - // push base pointer - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Register(STACK_POINTER_BASE_REGISTER), - })); - // move base - // rbp = rsp - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Register(STACK_POINTER_REGISTER), - operand_to: Operand::Register(STACK_POINTER_BASE_REGISTER), - })); - // here, [rbp-1] is old base pointer - // here, [rbp-2] is return address - - // body - self.body.emit(instructions); - - // end of body - // if return type is void, add return statement - // else, add panic statement for missing return statement - if instructions.get_true_typeinfo(&self.return_type) == TypeInfo::Void { - // force add return statement - let return_statement = StmtReturn { expr: None }; - return_statement.emit(instructions); - } else { - // panic - instructions.push(Instruction::Panic(Panic { - message: format!( - "Function {} must return a {:?} value", - &self.name, &self.return_type - ), - })); - } - - instructions.pop_scope(); - instructions.function_scope = None; - } -} #[derive(Debug, Clone)] pub struct TranslationUnit { pub statements: Vec, } -impl TranslationUnit { - pub fn emit(&self, instructions: &mut InstructionGenerator) { - for statement in &self.statements { - statement.emit(instructions); - } - - // find main function - let _main = instructions - .functions - .get("main") - .expect("main function not found"); - - let startaddress = instructions.instructions.len(); - instructions.start_address = startaddress; - instructions.push(Instruction::Call(Call { - label: "main".to_string(), - })); - } -} diff --git a/src/ast/typename.rs b/src/ast/typename.rs deleted file mode 100644 index 75fa1cc..0000000 --- a/src/ast/typename.rs +++ /dev/null @@ -1,349 +0,0 @@ -use std::collections::HashMap; - -use generation::InstructionGenerator; - -use crate::virtualmachine::instruction::operand::Operand; -use crate::virtualmachine::{ - instruction::*, program::STACK_POINTER_REGISTER, variable::VariableData, -}; - -use super::expression::Expression; - -#[derive(Debug, Clone, PartialEq)] -pub enum TypeInfo { - Void, - Int8, - Int16, - Int32, - Int64, - UInt8, - UInt16, - UInt32, - UInt64, - Float32, - Float64, - Struct(StructInfo), - Union(UnionInfo), - Enum(EnumInfo), - Pointer(Box), - Array(Box, Option), - Function(Box, Vec), - Const(Box), - - // for typedef - // temporary store the name of the type; will be replaced by the actual type in emitting - Identifier(String), -} -impl Default for TypeInfo { - fn default() -> Self { - TypeInfo::Int32 - } -} -impl TypeInfo { - pub fn sizeof(&self) -> usize { - match self { - TypeInfo::Void => panic!("sizeof(void) is invalid"), - TypeInfo::Int8 => 1, - TypeInfo::Int16 => 2, - TypeInfo::Int32 => 4, - TypeInfo::Int64 => 8, - TypeInfo::UInt8 => 1, - TypeInfo::UInt16 => 2, - TypeInfo::UInt32 => 4, - TypeInfo::UInt64 => 8, - TypeInfo::Float32 => 4, - TypeInfo::Float64 => 8, - TypeInfo::Struct(info) => info.sizeof(), - TypeInfo::Union(info) => info.sizeof(), - TypeInfo::Enum(_) => 8, - TypeInfo::Pointer(_) => 8, - TypeInfo::Array(info, size) => { - info.sizeof() * size.expect("sizeof: Array size is not defined") - } - TypeInfo::Function(_, _) => panic!("sizeof(function) is invalid"), - TypeInfo::Identifier(_) => panic!("sizeof(identifier) is invalid"), - TypeInfo::Const(t) => t.sizeof(), - } - } - pub fn number_of_primitives(&self) -> usize { - match self { - TypeInfo::Void => 0, - TypeInfo::Int8 | TypeInfo::Int16 | TypeInfo::Int32 | TypeInfo::Int64 => 1, - TypeInfo::UInt8 | TypeInfo::UInt16 | TypeInfo::UInt32 | TypeInfo::UInt64 => 1, - TypeInfo::Float32 | TypeInfo::Float64 => 1, - TypeInfo::Struct(structinfo) => structinfo.number_of_primitives(), - TypeInfo::Pointer(_) => 1, - TypeInfo::Array(info, Some(size)) => info.number_of_primitives() * size, - TypeInfo::Const(t) => t.number_of_primitives(), - _ => panic!("number_of_primitives: unsupported type: {:?}", self), - } - } - // push default value to the stack - pub fn emit_default(&self, instructions: &mut InstructionGenerator) { - match self { - TypeInfo::UInt8 => instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Value(VariableData::UInt8(0)), - })), - TypeInfo::Int8 => instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Value(VariableData::Int8(0)), - })), - - TypeInfo::UInt16 => instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Value(VariableData::UInt16(0)), - })), - TypeInfo::Int16 => instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Value(VariableData::Int16(0)), - })), - - TypeInfo::UInt32 => instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Value(VariableData::UInt32(0)), - })), - TypeInfo::Int32 => instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Value(VariableData::Int32(0)), - })), - - TypeInfo::UInt64 => instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Value(VariableData::UInt64(0)), - })), - TypeInfo::Int64 => instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Value(VariableData::Int64(0)), - })), - - TypeInfo::Float32 => instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Value(VariableData::Float32(0.0)), - })), - - TypeInfo::Float64 => instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Value(VariableData::Float64(0.0)), - })), - - TypeInfo::Pointer(_) => instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Value(VariableData::UInt64(0)), - })), - - TypeInfo::Array(t, Some(n)) => { - for _ in 0..*n { - t.emit_default(instructions); - } - } - - TypeInfo::Struct(info) => info.emit_default(instructions), - - TypeInfo::Const(t) => t.emit_default(instructions), - - _ => panic!("emit_default: unsupported type: {:?}", self), - } - } - - // initialize this type with the given initializer - // and push to stack - pub fn emit_init(&self, instructions: &mut InstructionGenerator, initializer: &Expression) { - match self { - TypeInfo::Array(t, Some(n)) => { - let initializer = match initializer { - Expression::InitializerList(initializer) => initializer, - _ => { - unreachable!( - "TypeInfo::emit_init: initializer is not InitializerListExpression" - ) - } - }; - - if initializer.initializers.len() > *n { - panic!( - "Array initialization overflow: expected {}, got {}", - n, - initializer.initializers.len() - ); - } - - for i in 0..initializer.initializers.len() { - t.emit_init(instructions, &initializer.initializers[i]); - } - - let remaining = *n - initializer.initializers.len(); - for _ in 0..remaining { - t.emit_default(instructions); - } - } - - TypeInfo::Struct(info) => info.emit_init(instructions, &initializer), - - TypeInfo::Const(t) => t.emit_init(instructions, &initializer), - - TypeInfo::UInt8 - | TypeInfo::Int8 - | TypeInfo::UInt16 - | TypeInfo::Int16 - | TypeInfo::UInt32 - | TypeInfo::Int32 - | TypeInfo::UInt64 - | TypeInfo::Int64 - | TypeInfo::Float32 - | TypeInfo::Float64 - | TypeInfo::Pointer(_) => { - // check if it is initializer list - match initializer { - Expression::InitializerList(initializer) => { - if initializer.initializers.len() != 1 { - panic!( - "TypeInfo::emit_init: initializer length mismatch: expected 1, got {}", - initializer.initializers.len() - ); - } - self.emit_init(instructions, &initializer.initializers[0]); - } - _ => { - // register0 = initial value - initializer.emit(instructions); - - // register1 = (type-casting) register0 - if initializer.is_return_reference(instructions) { - instructions.push(Instruction::Assign(Assign { - lhs_type: self.clone(), - lhs: Operand::Register(1), - rhs: Operand::Derefed(0, 0), - })); - } else { - instructions.push(Instruction::Assign(Assign { - lhs_type: self.clone(), - lhs: Operand::Register(1), - rhs: Operand::Register(0), - })); - } - // push register1 to stack - instructions.push(Instruction::PushStack(PushStack { - operand: Operand::Register(1), - })); - } - } - } - _ => panic!("emit_init: unsupported type: {:?}", self), - } - } - - // remove outermost const recursively - pub fn remove_const(&self) -> TypeInfo { - match self { - TypeInfo::Const(t) => t.remove_const(), - _ => self.clone(), - } - } - - pub fn add_const(&self) -> TypeInfo { - match self { - TypeInfo::Const(_) => self.clone(), - _ => TypeInfo::Const(Box::new(self.clone())), - } - } - pub fn is_const(&self) -> bool { - match self { - TypeInfo::Const(_) => true, - _ => false, - } - } -} - -#[derive(Debug, Clone, PartialEq)] -pub struct StructInfo { - pub name: Option, - pub fields: Option>, -} -impl StructInfo { - pub fn sizeof(&self) -> usize { - let mut size: usize = 0; - for (t, _, _) in self.fields.as_ref().unwrap() { - size += t.sizeof(); - } - size - } - pub fn number_of_primitives(&self) -> usize { - let mut count: usize = 0; - for (t, _, _) in self.fields.as_ref().unwrap() { - count += t.number_of_primitives(); - } - count - } - pub fn emit_default(&self, instructions: &mut InstructionGenerator) { - for (t, _, _) in self.fields.as_ref().unwrap() { - t.emit_default(instructions); - } - } - pub fn emit_init(&self, instructions: &mut InstructionGenerator, initializer: &Expression) { - match initializer { - Expression::InitializerList(initializer) => { - // struct init with initializer - - if initializer.initializers.len() != self.fields.as_ref().unwrap().len() { - panic!( - "StructInfo::emit_init: initializer length mismatch: expected {}, got {}", - self.fields.as_ref().unwrap().len(), - initializer.initializers.len() - ); - } - - for i in 0..initializer.initializers.len() { - let (t, _, _) = &self.fields.as_ref().unwrap()[i]; - instructions - .get_true_typeinfo(t) - .emit_init(instructions, &initializer.initializers[i]); - } - } - _ => { - // struct init with other struct - if let TypeInfo::Struct(rhs_type) = initializer.get_typeinfo(instructions) { - if self != &rhs_type { - panic!("struct init: type mismatch1"); - } - - let primitive_count = rhs_type.number_of_primitives(); - - initializer.emit(instructions); - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Register(0), - operand_to: Operand::Register(1), - })); - - // start address of new struct - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Register(STACK_POINTER_REGISTER), - operand_to: Operand::Register(0), - })); - // alloc stack - instructions.push(Instruction::AddAssign(AddAssign { - lhs: Operand::Register(STACK_POINTER_REGISTER), - rhs: Operand::Value(VariableData::UInt64(primitive_count as u64)), - })); - - instructions.push(Instruction::AssignStruct(AssignStruct { - lhs: Operand::Register(0), - rhs: Operand::Register(1), - count: primitive_count, - })); - } else { - panic!("struct init: type mismatch2"); - } - } - } - } -} -#[derive(Debug, Clone, PartialEq)] -pub struct UnionInfo { - pub name: Option, - pub fields: Option>, -} -impl UnionInfo { - pub fn sizeof(&self) -> usize { - let mut size: usize = 0; - for (_, field) in self.fields.as_ref().unwrap() { - size = size.max(field.sizeof()); - } - size - } -} - -#[derive(Debug, Clone, PartialEq)] -pub struct EnumInfo { - pub name: Option, - pub fields: Option>, -} diff --git a/src/token/token.rs b/src/token/token.rs index 82bca15..016df68 100644 --- a/src/token/token.rs +++ b/src/token/token.rs @@ -1,4 +1,4 @@ -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, Clone)] pub enum Token { Others(char), // any other character that failed to parse; Identifier(String), @@ -100,6 +100,20 @@ pub enum Token { Pipe, Question, Whitespace, // one or more whitespaces + + Eof, +} + +impl PartialEq for Token { + fn eq(&self, other: &Self) -> bool { + std::mem::discriminant(self) == std::mem::discriminant(other) + } +} +impl Eq for Token {} +impl std::hash::Hash for Token { + fn hash(&self, state: &mut H) { + std::mem::discriminant(self).hash(state); + } } use rusty_parser as rp; From f93ad7d38290eafd717bd87aafcf8df4792100dd Mon Sep 17 00:00:00 2001 From: Taehwan Kim Date: Mon, 28 Oct 2024 22:42:04 +0900 Subject: [PATCH 02/10] add empty functions for future ast -> ast2 conversion interface --- src/ast/mod.rs | 27 ++- src/ast2/context.rs | 494 +++++++++++++++++++++++++++++++++++++++++ src/ast2/declarator.rs | 8 + src/ast2/error.rs | 1 + src/ast2/expression.rs | 1 + src/ast2/mod.rs | 14 ++ src/ast2/scope.rs | 0 src/ast2/statement.rs | 1 + src/ast2/typename.rs | 41 ++++ src/ast2/variable.rs | 3 + src/main.rs | 1 + 11 files changed, 590 insertions(+), 1 deletion(-) create mode 100644 src/ast2/context.rs create mode 100644 src/ast2/declarator.rs create mode 100644 src/ast2/error.rs create mode 100644 src/ast2/expression.rs create mode 100644 src/ast2/mod.rs create mode 100644 src/ast2/scope.rs create mode 100644 src/ast2/statement.rs create mode 100644 src/ast2/typename.rs create mode 100644 src/ast2/variable.rs diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 50b622d..3049996 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -3,8 +3,17 @@ mod expression; mod parser_lr; mod statement; -pub use declarator::DeclarationSpecifier; +pub use declarator::DeclArrayFixed; +pub use declarator::DeclArrayUnbounded; +pub use declarator::DeclConst; +pub use declarator::DeclFunction; +pub use declarator::DeclIdentifier; +pub use declarator::DeclInit; +pub use declarator::DeclPointer; +pub use declarator::DeclVolatile; pub use declarator::Declarator; + +pub use declarator::DeclarationSpecifier; pub use declarator::EnumSpecifier; pub use declarator::Enumerator; pub use declarator::ParameterDeclaration; @@ -17,10 +26,19 @@ pub use declarator::TypeQualifier; pub use declarator::TypeSpecifier; pub use declarator::Typename; pub use expression::ExprArrow; +pub use expression::ExprBinary; pub use expression::ExprBracket; pub use expression::ExprCast; pub use expression::ExprConditional; +pub use expression::ExprConstantCharacter; pub use expression::ExprConstantDouble; +pub use expression::ExprConstantFloat; +pub use expression::ExprConstantInteger; +pub use expression::ExprConstantLong; +pub use expression::ExprConstantUnsignedInteger; +pub use expression::ExprConstantUnsignedLong; +pub use expression::ExprIdentifier; +pub use expression::ExprInitializerList; pub use expression::ExprMember; pub use expression::ExprParen; pub use expression::ExprSizeOfExpr; @@ -30,12 +48,19 @@ pub use expression::ExprUnary; pub use expression::Expression; pub use statement::Statement; pub use statement::StmtBreak; +pub use statement::StmtCase; +pub use statement::StmtCompound; pub use statement::StmtContinue; +pub use statement::StmtDeclaration; +pub use statement::StmtDefault; pub use statement::StmtDoWhile; +pub use statement::StmtExpression; pub use statement::StmtFor; +pub use statement::StmtFunctionDefinition; pub use statement::StmtGoto; pub use statement::StmtIf; pub use statement::StmtLabeled; +pub use statement::StmtNull; pub use statement::StmtReturn; pub use statement::StmtSwitch; pub use statement::StmtWhile; diff --git a/src/ast2/context.rs b/src/ast2/context.rs new file mode 100644 index 0000000..3ac679d --- /dev/null +++ b/src/ast2/context.rs @@ -0,0 +1,494 @@ +use super::expression; +use super::statement; +use super::CVType; +use super::CombinedDeclarator; +use super::ConversionError; +use super::Expression; +use super::Statement; +use crate::ast; + +pub struct Context { + // pub function_scope: Option, + // pub scopes: Vec, + // pub scope_counter: usize, + + // pub labels: HashMap>>, +} + +impl Context { + pub fn new() -> Self { + Context { + // scopes: Vec::new(), + // scope_counter: 0, + // labels: Default::default(), + } + } + + /// return index on local stack for new variable + /* + fn new_offset(&self) -> usize { + for parent in self.scopes.iter().rev() { + match parent { + Scope::Block(blk) => return blk.offset + blk.variables.len(), + Scope::Function(_) => return 0, + } + } + 0 + } + pub fn begin_scope(&mut self, is_loop: bool) { + let offset = self.new_offset(); + self.scope_counter += 1; + self.scopes.push(Scope::Block(ScopeBlock { + id: self.scope_counter, + max_variables: 0, + offset, + variables: Vec::new(), + is_loop, + labels: Vec::new(), + })); + } + /// close all local variable scopes, count up variables and re calculate stack size. + fn end_scope(&mut self) -> Scope { + let scope = self.scopes.pop().unwrap(); + + if let Scope::Block(blk) = &scope { + for label in blk.labels.iter() { + self.labels.remove(label); + } + match self.scopes.last_mut() { + Some(Scope::Block(parent)) => { + let vars = parent.variables.len() + blk.max_variables; + parent.max_variables = parent.max_variables.max(vars); + } + Some(Scope::Function(parent)) => { + parent.max_variables = parent.max_variables.max(blk.max_variables); + } + _ => {} + } + } else { + unreachable!("end_scope - block scope not opened?"); + } + + scope + } + /// return local stack offset + fn begin_variable_scope(&mut self, name: String) -> Rc> { + if let Some(Scope::Block(blk)) = self.scopes.last_mut() { + let offset = blk.offset + blk.variables.len(); + let varinfo = Rc::new(RefCell::new(VariableInfo { + name, + is_reference: false, + offset, + })); + blk.variables.push(Rc::clone(&varinfo)); + blk.max_variables = blk.max_variables.max(blk.variables.len()); + varinfo + } else { + unreachable!("begin_variable_scope - block scope not opened?"); + } + } + /// search for local variable name `name` + fn search_local_variable(&mut self, name: &str) -> Option { + let mut function_scopes = Vec::new(); + let mut found = None; + 'a: for scope in self.scopes.iter_mut().rev() { + match scope { + Scope::Block(blk) => { + for var in blk.variables.iter().rev() { + if var.borrow().name == name { + found = Some(ExprLocalVariable::Stack( + var.borrow().offset, + name.to_string(), + )); + break 'a; + } + } + } + Scope::Function(func) => { + for (upvalue_idx, upvalue) in func.upvalues.iter().enumerate() { + if upvalue.name.as_str() == name { + found = Some(ExprLocalVariable::Upvalue(upvalue_idx, name.to_string())); + break 'a; + } + } + function_scopes.push(func); + } + } + } + if let Some(mut found) = found { + for scope in function_scopes.into_iter().rev() { + let upvalue_idx = scope.upvalues.len(); + scope.upvalues.push(UpvalueInfo { + name: name.to_string(), + from: found, + }); + found = ExprLocalVariable::Upvalue(upvalue_idx, name.to_string()); + } + Some(found) + } else { + None + } + } + fn begin_function_scope(&mut self, variadic: bool) { + self.scope_counter += 1; + self.scopes.push(Scope::Function(ScopeFunction { + id: self.scope_counter, + max_variables: 0, + upvalues: Vec::new(), + variadic, + })); + } + fn end_function_scope(&mut self) -> ScopeFunction { + if let Some(Scope::Function(scope)) = self.scopes.pop() { + scope + } else { + unreachable!("end_function_scope - function scope not opened? - 2"); + } + } + fn nearest_function_scope(&mut self) -> Option<&mut ScopeFunction> { + for scope in self.scopes.iter_mut().rev() { + match scope { + Scope::Function(func) => return Some(func), + _ => {} + } + } + None + } + + fn scope_tree(&self) -> Vec { + let mut tree = Vec::new(); + for scope in self.scopes.iter().rev() { + match scope { + Scope::Block(blk) => tree.push(blk.id), + Scope::Function(_) => break, + } + } + tree.reverse(); + tree + } + */ + + // pub fn process(&mut self, block: lua_parser::Block) -> Result { + // self.begin_scope(false); + // self.process_block(block, false, false) + // } + + pub fn process_statement( + &mut self, + statement: ast::Statement, + ) -> Result { + match statement { + ast::Statement::Null(stmt) => self.process_statement_null(stmt), + ast::Statement::Expression(stmt) => self.process_statement_expression(stmt), + ast::Statement::Labeled(stmt) => self.process_statement_labeled(stmt), + ast::Statement::Compound(stmt) => self.process_statement_compound(stmt), + ast::Statement::If(stmt) => self.process_statement_if(stmt), + ast::Statement::Switch(stmt) => self.process_statement_switch(stmt), + ast::Statement::Case(stmt) => self.process_statement_case(stmt), + ast::Statement::Default(stmt) => self.process_statement_default(stmt), + ast::Statement::Continue(stmt) => self.process_statement_continue(stmt), + ast::Statement::Break(stmt) => self.process_statement_break(stmt), + ast::Statement::While(stmt) => self.process_statement_while(stmt), + ast::Statement::DoWhile(stmt) => self.process_statement_dowhile(stmt), + ast::Statement::For(stmt) => self.process_statement_for(stmt), + ast::Statement::Goto(stmt) => self.process_statement_goto(stmt), + ast::Statement::Return(stmt) => self.process_statement_return(stmt), + ast::Statement::Declaration(stmt) => self.process_statement_declaration(stmt), + ast::Statement::FunctionDefinition(stmt) => { + self.process_statement_functiondefinition(stmt) + } + } + } + + pub fn process_expression( + &mut self, + expression: ast::Expression, + ) -> Result { + match expression { + ast::Expression::Identifier(expr) => self.process_expression_identifier(expr), + ast::Expression::ConstantCharacter(expr) => { + self.process_expression_constantcharacter(expr) + } + ast::Expression::ConstantInteger(expr) => self.process_expression_constantinteger(expr), + ast::Expression::ConstantUnsignedInteger(expr) => { + self.process_expression_constantunsignedinteger(expr) + } + ast::Expression::ConstantLong(expr) => self.process_expression_constantlong(expr), + ast::Expression::ConstantUnsignedLong(expr) => { + self.process_expression_constantunsignedlong(expr) + } + ast::Expression::ConstantFloat(expr) => self.process_expression_constantfloat(expr), + ast::Expression::ConstantDouble(expr) => self.process_expression_constantdouble(expr), + ast::Expression::String(expr) => self.process_expression_string(expr), + ast::Expression::Member(expr) => self.process_expression_member(expr), + ast::Expression::Arrow(expr) => self.process_expression_arrow(expr), + ast::Expression::Bracket(expr) => self.process_expression_bracket(expr), + ast::Expression::Paren(expr) => self.process_expression_paren(expr), + ast::Expression::Cast(expr) => self.process_expression_cast(expr), + ast::Expression::SizeofType(expr) => self.process_expression_sizeoftype(expr), + ast::Expression::SizeofExpr(expr) => self.process_expression_sizeofexpr(expr), + ast::Expression::Conditional(expr) => self.process_expression_conditional(expr), + ast::Expression::Unary(expr) => self.process_expression_unary(expr), + ast::Expression::Binary(expr) => self.process_expression_binary(expr), + ast::Expression::InitializerList(expr) => self.process_expression_initializerlist(expr), + } + } + + pub fn process_declarator( + &mut self, + declarator: ast::Declarator, + base_type: CVType, + ) -> Result { + match declarator { + ast::Declarator::Identifier(decl) => { + self.process_declarator_identifier(decl, base_type) + } + ast::Declarator::Pointer(decl) => self.process_declarator_pointer(decl, base_type), + ast::Declarator::ArrayFixed(decl) => { + self.process_declarator_array_fixed(decl, base_type) + } + ast::Declarator::ArrayUnbounded(decl) => { + self.process_declarator_array_unbounded(decl, base_type) + } + ast::Declarator::Function(decl) => self.process_declarator_function(decl, base_type), + ast::Declarator::Const(decl) => self.process_declarator_const(decl, base_type), + ast::Declarator::Volatile(decl) => self.process_declarator_volatile(decl, base_type), + } + } +} + +impl Context { + pub(crate) fn process_statement_null( + &mut self, + stmt: ast::StmtNull, + ) -> Result { + } + pub(crate) fn process_statement_expression( + &mut self, + stmt: ast::StmtExpression, + ) -> Result { + } + pub(crate) fn process_statement_labeled( + &mut self, + stmt: ast::StmtLabeled, + ) -> Result { + } + pub(crate) fn process_statement_compound( + &mut self, + stmt: ast::StmtCompound, + ) -> Result { + } + pub(crate) fn process_statement_if( + &mut self, + stmt: ast::StmtIf, + ) -> Result { + } + pub(crate) fn process_statement_switch( + &mut self, + stmt: ast::StmtSwitch, + ) -> Result { + } + pub(crate) fn process_statement_case( + &mut self, + stmt: ast::StmtCase, + ) -> Result { + } + pub(crate) fn process_statement_default( + &mut self, + stmt: ast::StmtDefault, + ) -> Result { + } + pub(crate) fn process_statement_continue( + &mut self, + stmt: ast::StmtContinue, + ) -> Result { + } + pub(crate) fn process_statement_break( + &mut self, + stmt: ast::StmtBreak, + ) -> Result { + } + pub(crate) fn process_statement_while( + &mut self, + stmt: ast::StmtWhile, + ) -> Result { + } + pub(crate) fn process_statement_dowhile( + &mut self, + stmt: ast::StmtDoWhile, + ) -> Result { + } + pub(crate) fn process_statement_for( + &mut self, + stmt: ast::StmtFor, + ) -> Result { + } + pub(crate) fn process_statement_goto( + &mut self, + stmt: ast::StmtGoto, + ) -> Result { + } + pub(crate) fn process_statement_return( + &mut self, + stmt: ast::StmtReturn, + ) -> Result { + } + pub(crate) fn process_statement_declaration( + &mut self, + stmt: ast::StmtDeclaration, + ) -> Result { + } + pub(crate) fn process_statement_functiondefinition( + &mut self, + stmt: ast::StmtFunctionDefinition, + ) -> Result { + } +} + +impl Context { + pub(crate) fn process_expression_identifier( + &mut self, + expr: ast::ExprIdentifier, + ) -> Result { + } + pub(crate) fn process_expression_constantcharacter( + &mut self, + expr: ast::ExprConstantCharacter, + ) -> Result { + } + pub(crate) fn process_expression_constantinteger( + &mut self, + expr: ast::ExprConstantInteger, + ) -> Result { + } + pub(crate) fn process_expression_constantunsignedinteger( + &mut self, + expr: ast::ExprConstantUnsignedInteger, + ) -> Result { + } + pub(crate) fn process_expression_constantlong( + &mut self, + expr: ast::ExprConstantLong, + ) -> Result { + } + pub(crate) fn process_expression_constantunsignedlong( + &mut self, + expr: ast::ExprConstantUnsignedLong, + ) -> Result { + } + pub(crate) fn process_expression_constantfloat( + &mut self, + expr: ast::ExprConstantFloat, + ) -> Result { + } + pub(crate) fn process_expression_constantdouble( + &mut self, + expr: ast::ExprConstantDouble, + ) -> Result { + } + pub(crate) fn process_expression_string( + &mut self, + expr: ast::ExprString, + ) -> Result { + } + pub(crate) fn process_expression_member( + &mut self, + expr: ast::ExprMember, + ) -> Result { + } + pub(crate) fn process_expression_arrow( + &mut self, + expr: ast::ExprArrow, + ) -> Result { + } + pub(crate) fn process_expression_bracket( + &mut self, + expr: ast::ExprBracket, + ) -> Result { + } + pub(crate) fn process_expression_paren( + &mut self, + expr: ast::ExprParen, + ) -> Result { + } + pub(crate) fn process_expression_cast( + &mut self, + expr: ast::ExprCast, + ) -> Result { + } + pub(crate) fn process_expression_sizeoftype( + &mut self, + expr: ast::ExprSizeOfType, + ) -> Result { + } + pub(crate) fn process_expression_sizeofexpr( + &mut self, + expr: ast::ExprSizeOfExpr, + ) -> Result { + } + pub(crate) fn process_expression_conditional( + &mut self, + expr: ast::ExprConditional, + ) -> Result { + } + pub(crate) fn process_expression_unary( + &mut self, + expr: ast::ExprUnary, + ) -> Result { + } + pub(crate) fn process_expression_binary( + &mut self, + expr: ast::ExprBinary, + ) -> Result { + } + pub(crate) fn process_expression_initializerlist( + &mut self, + expr: ast::ExprInitializerList, + ) -> Result { + } +} + +impl Context { + pub(crate) fn process_declarator_identifier( + &mut self, + decl: ast::DeclIdentifier, + base_type: CVType, + ) -> Result { + } + pub(crate) fn process_declarator_pointer( + &mut self, + decl: ast::DeclPointer, + base_type: CVType, + ) -> Result { + } + pub(crate) fn process_declarator_array_fixed( + &mut self, + decl: ast::DeclArrayFixed, + base_type: CVType, + ) -> Result { + } + pub(crate) fn process_declarator_array_unbounded( + &mut self, + decl: ast::DeclArrayUnbounded, + base_type: CVType, + ) -> Result { + } + pub(crate) fn process_declarator_function( + &mut self, + decl: ast::DeclFunction, + base_type: CVType, + ) -> Result { + } + pub(crate) fn process_declarator_const( + &mut self, + decl: ast::DeclConst, + base_type: CVType, + ) -> Result { + } + pub(crate) fn process_declarator_volatile( + &mut self, + decl: ast::DeclVolatile, + base_type: CVType, + ) -> Result { + } +} diff --git a/src/ast2/declarator.rs b/src/ast2/declarator.rs new file mode 100644 index 0000000..531e74d --- /dev/null +++ b/src/ast2/declarator.rs @@ -0,0 +1,8 @@ +use super::CVType; + +#[derive(Debug, Clone)] +pub struct CombinedDeclarator { + /// variable name, for direct declarator + pub name: Option, + pub type_: CVType, +} diff --git a/src/ast2/error.rs b/src/ast2/error.rs new file mode 100644 index 0000000..ff360d1 --- /dev/null +++ b/src/ast2/error.rs @@ -0,0 +1 @@ +pub enum ConversionError {} diff --git a/src/ast2/expression.rs b/src/ast2/expression.rs new file mode 100644 index 0000000..05ce0c5 --- /dev/null +++ b/src/ast2/expression.rs @@ -0,0 +1 @@ +pub enum Expression {} diff --git a/src/ast2/mod.rs b/src/ast2/mod.rs new file mode 100644 index 0000000..feae52b --- /dev/null +++ b/src/ast2/mod.rs @@ -0,0 +1,14 @@ +mod context; +mod declarator; +mod error; +mod expression; +mod scope; +mod statement; +mod typename; +mod variable; + +pub use declarator::CombinedDeclarator; +pub use error::ConversionError; +pub use expression::Expression; +pub use statement::Statement; +pub use typename::CVType; diff --git a/src/ast2/scope.rs b/src/ast2/scope.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/ast2/statement.rs b/src/ast2/statement.rs new file mode 100644 index 0000000..818f600 --- /dev/null +++ b/src/ast2/statement.rs @@ -0,0 +1 @@ +pub enum Statement {} diff --git a/src/ast2/typename.rs b/src/ast2/typename.rs new file mode 100644 index 0000000..cf12954 --- /dev/null +++ b/src/ast2/typename.rs @@ -0,0 +1,41 @@ +#[derive(Debug, Clone)] +pub enum PrimitiveType { + Void, + UInt8, + UInt16, + UInt32, + UInt64, + Int8, + Int16, + Int32, + Int64, + Float32, + Float64, + + Struct, + Union, + Enum, + + Pointer(Box), + Array(ArrayType), + Function(FunctionType), +} + +#[derive(Debug, Clone)] +pub struct ArrayType { + pub type_: Box, + pub size: usize, +} +#[derive(Debug, Clone)] +pub struct FunctionType { + // maybe no need CV qualifier for return type? + pub return_type: Box, + pub args: Vec, +} + +#[derive(Debug, Clone)] +pub struct CVType { + pub type_: PrimitiveType, + pub const_: bool, + pub volatile: bool, +} diff --git a/src/ast2/variable.rs b/src/ast2/variable.rs new file mode 100644 index 0000000..7b5d5f3 --- /dev/null +++ b/src/ast2/variable.rs @@ -0,0 +1,3 @@ +pub struct VariableInfo { + pub name: String, +} diff --git a/src/main.rs b/src/main.rs index b77efaf..130dcf1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ use virtualmachine::instruction::generation::InstructionGenerator; use virtualmachine::program::VirtualMachine; mod ast; +mod ast2; mod preprocess; mod token; mod virtualmachine; From 48d2ea221ee9566f8dafaf2c3943c4c21ea79d26 Mon Sep 17 00:00:00 2001 From: ehwan Date: Tue, 29 Oct 2024 15:32:54 +0900 Subject: [PATCH 03/10] WIP some declarator and statements --- src/ast/mod.rs | 4 + src/ast/parser_lr.rs | 6 +- src/ast/statement.rs | 2 +- src/ast2/context.rs | 538 ++++++++++++++++++++++++++++++----------- src/ast2/error.rs | 22 +- src/ast2/expression.rs | 55 ++++- src/ast2/label.rs | 4 + src/ast2/mod.rs | 23 +- src/ast2/scope.rs | 63 +++++ src/ast2/statement.rs | 107 +++++++- src/ast2/typename.rs | 28 +++ 11 files changed, 695 insertions(+), 157 deletions(-) create mode 100644 src/ast2/label.rs diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 3049996..8d58477 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -25,8 +25,10 @@ pub use declarator::StructOrUnionSpecifier; pub use declarator::TypeQualifier; pub use declarator::TypeSpecifier; pub use declarator::Typename; + pub use expression::ExprArrow; pub use expression::ExprBinary; +pub use expression::ExprBinaryOperator; pub use expression::ExprBracket; pub use expression::ExprCast; pub use expression::ExprConditional; @@ -45,7 +47,9 @@ pub use expression::ExprSizeOfExpr; pub use expression::ExprSizeOfType; pub use expression::ExprString; pub use expression::ExprUnary; +pub use expression::ExprUnaryOperator; pub use expression::Expression; + pub use statement::Statement; pub use statement::StmtBreak; pub use statement::StmtCase; diff --git a/src/ast/parser_lr.rs b/src/ast/parser_lr.rs index 390155b..48a6ff7 100644 --- a/src/ast/parser_lr.rs +++ b/src/ast/parser_lr.rs @@ -708,20 +708,18 @@ iteration_statement( Statement ) }) } | for_ lparen init=expression_statement cond=expression_statement rparen body=statement { - let Statement::Expression(init) = init else { unreachable!() }; let Statement::Expression(cond) = cond else { unreachable!() }; Statement::For( statement::StmtFor{ - init: init.expression, + init: Box::new(init), cond: cond.expression, next: None, statement: Box::new(body), }) } | for_ lparen init=expression_statement cond=expression_statement next=expression rparen body=statement { - let Statement::Expression(init) = init else { unreachable!() }; let Statement::Expression(cond) = cond else { unreachable!() }; Statement::For( statement::StmtFor{ - init: init.expression, + init: Box::new(init), cond: cond.expression, next: Some(next), statement: Box::new(body), diff --git a/src/ast/statement.rs b/src/ast/statement.rs index 179a0b2..c4227f7 100644 --- a/src/ast/statement.rs +++ b/src/ast/statement.rs @@ -112,7 +112,7 @@ pub struct StmtDoWhile { /// since init is expression, must declare variable before entering for loop #[derive(Debug, Clone)] pub struct StmtFor { - pub init: Expression, + pub init: Box, pub cond: Expression, pub next: Option, pub statement: Box, diff --git a/src/ast2/context.rs b/src/ast2/context.rs index 3ac679d..33a4716 100644 --- a/src/ast2/context.rs +++ b/src/ast2/context.rs @@ -1,177 +1,132 @@ +use std::cell::RefCell; +use std::rc::Rc; + use super::expression; use super::statement; +use super::ArrayType; use super::CVType; use super::CombinedDeclarator; use super::ConversionError; use super::Expression; +use super::FunctionType; +use super::PrimitiveType; use super::Statement; +use super::StmtSwitchCase; use crate::ast; -pub struct Context { - // pub function_scope: Option, - // pub scopes: Vec, - // pub scope_counter: usize, +use super::scope::BlockScope; +use super::scope::FunctionScope; +use super::scope::GlobalScope; +use super::scope::LoopScope; +use super::scope::Scope; +use super::scope::SwitchScope; +use super::scope::VariableScope; - // pub labels: HashMap>>, +use super::LabelInfo; + +pub struct Context { + /// for unique scope id generation + pub scope_counter: usize, + pub global_scope: GlobalScope, + pub function_scope: Option, + pub scopes: Vec, } impl Context { pub fn new() -> Self { Context { - // scopes: Vec::new(), - // scope_counter: 0, - // labels: Default::default(), + scope_counter: 0, + global_scope: GlobalScope::new(), + function_scope: None, + scopes: Vec::new(), } } - /// return index on local stack for new variable - /* - fn new_offset(&self) -> usize { - for parent in self.scopes.iter().rev() { - match parent { - Scope::Block(blk) => return blk.offset + blk.variables.len(), - Scope::Function(_) => return 0, - } - } - 0 - } - pub fn begin_scope(&mut self, is_loop: bool) { - let offset = self.new_offset(); + /// generate unique scope id + fn generate_scope_id(&mut self) -> usize { self.scope_counter += 1; - self.scopes.push(Scope::Block(ScopeBlock { - id: self.scope_counter, - max_variables: 0, - offset, - variables: Vec::new(), - is_loop, - labels: Vec::new(), - })); - } - /// close all local variable scopes, count up variables and re calculate stack size. - fn end_scope(&mut self) -> Scope { - let scope = self.scopes.pop().unwrap(); - - if let Scope::Block(blk) = &scope { - for label in blk.labels.iter() { - self.labels.remove(label); - } - match self.scopes.last_mut() { - Some(Scope::Block(parent)) => { - let vars = parent.variables.len() + blk.max_variables; - parent.max_variables = parent.max_variables.max(vars); - } - Some(Scope::Function(parent)) => { - parent.max_variables = parent.max_variables.max(blk.max_variables); - } + self.scope_counter + } + fn begin_switch_scope(&mut self) -> Result<(), ConversionError> { + let scope = SwitchScope { + id: self.generate_scope_id(), + default: false, + }; + self.scopes.push(Scope::Switch(scope)); + Ok(()) + } + fn nearest_switch_scope(&mut self) -> Option<&mut SwitchScope> { + for scope in self.scopes.iter_mut().rev() { + match scope { + Scope::Switch(scope) => return Some(scope), _ => {} } - } else { - unreachable!("end_scope - block scope not opened?"); } + None + } + fn end_switch_scope(&mut self) -> Result { + unimplemented!("end_switch_scope") + // must pop every variable scope until switch scope + } + fn begin_loop_scope(&mut self) -> Result<(), ConversionError> { + let scope = LoopScope { + id: self.generate_scope_id(), + }; + self.scopes.push(Scope::Loop(scope)); + Ok(()) + } + fn end_loop_scope(&mut self) -> Result { + unimplemented!("end_loop_scope") + // must pop every variable scope until loop scope + } - scope + fn begin_scope(&mut self) -> Result<(), ConversionError> { + let scope = BlockScope { + id: self.generate_scope_id(), + }; + self.scopes.push(Scope::Block(scope)); + Ok(()) } - /// return local stack offset - fn begin_variable_scope(&mut self, name: String) -> Rc> { - if let Some(Scope::Block(blk)) = self.scopes.last_mut() { - let offset = blk.offset + blk.variables.len(); - let varinfo = Rc::new(RefCell::new(VariableInfo { - name, - is_reference: false, - offset, - })); - blk.variables.push(Rc::clone(&varinfo)); - blk.max_variables = blk.max_variables.max(blk.variables.len()); - varinfo - } else { - unreachable!("begin_variable_scope - block scope not opened?"); - } + fn end_scope(&mut self) -> Result { + unimplemented!("end_scope") } - /// search for local variable name `name` - fn search_local_variable(&mut self, name: &str) -> Option { - let mut function_scopes = Vec::new(); - let mut found = None; - 'a: for scope in self.scopes.iter_mut().rev() { - match scope { - Scope::Block(blk) => { - for var in blk.variables.iter().rev() { - if var.borrow().name == name { - found = Some(ExprLocalVariable::Stack( - var.borrow().offset, - name.to_string(), - )); - break 'a; - } - } - } - Scope::Function(func) => { - for (upvalue_idx, upvalue) in func.upvalues.iter().enumerate() { - if upvalue.name.as_str() == name { - found = Some(ExprLocalVariable::Upvalue(upvalue_idx, name.to_string())); - break 'a; - } - } - function_scopes.push(func); - } - } - } - if let Some(mut found) = found { - for scope in function_scopes.into_iter().rev() { - let upvalue_idx = scope.upvalues.len(); - scope.upvalues.push(UpvalueInfo { - name: name.to_string(), - from: found, - }); - found = ExprLocalVariable::Upvalue(upvalue_idx, name.to_string()); - } - Some(found) - } else { - None - } + + fn begin_function_scope( + &mut self, + name: String, + type_: FunctionType, + ) -> Result<(), ConversionError> { + unimplemented!("begin_function_scope") } - fn begin_function_scope(&mut self, variadic: bool) { - self.scope_counter += 1; - self.scopes.push(Scope::Function(ScopeFunction { - id: self.scope_counter, - max_variables: 0, - upvalues: Vec::new(), - variadic, - })); - } - fn end_function_scope(&mut self) -> ScopeFunction { - if let Some(Scope::Function(scope)) = self.scopes.pop() { - scope - } else { - unreachable!("end_function_scope - function scope not opened? - 2"); - } + fn end_function_scope(&mut self) -> Result { + unimplemented!("end_function_scope") } - fn nearest_function_scope(&mut self) -> Option<&mut ScopeFunction> { - for scope in self.scopes.iter_mut().rev() { + + fn begin_variable_scope(&mut self, name: String) -> Result<(), ConversionError> { + unimplemented!("begin_variable_scope") + } + + fn can_continue(&self) -> bool { + for scope in self.scopes.iter().rev() { match scope { - Scope::Function(func) => return Some(func), + Scope::Loop(_) => return true, _ => {} } } - None + false } - - fn scope_tree(&self) -> Vec { - let mut tree = Vec::new(); + fn can_break(&self) -> bool { for scope in self.scopes.iter().rev() { match scope { - Scope::Block(blk) => tree.push(blk.id), - Scope::Function(_) => break, + Scope::Loop(_) | Scope::Switch(_) => return true, + _ => {} } } - tree.reverse(); - tree + false + } + fn can_return(&self) -> bool { + self.function_scope.is_some() } - */ - - // pub fn process(&mut self, block: lua_parser::Block) -> Result { - // self.begin_scope(false); - // self.process_block(block, false, false) - // } pub fn process_statement( &mut self, @@ -257,81 +212,262 @@ impl Context { } } +// for statements impl Context { pub(crate) fn process_statement_null( &mut self, - stmt: ast::StmtNull, + _stmt: ast::StmtNull, ) -> Result { + Ok(Statement::None) } pub(crate) fn process_statement_expression( &mut self, stmt: ast::StmtExpression, ) -> Result { + Ok(Statement::Expression(statement::StmtExpression { + expression: self.process_expression(stmt.expression)?, + })) } pub(crate) fn process_statement_labeled( &mut self, stmt: ast::StmtLabeled, ) -> Result { + if let Some(function_scope) = &mut self.function_scope { + let label_info = LabelInfo { + name: stmt.label.clone(), + }; + let label_info = Rc::new(RefCell::new(label_info)); + if let Some(old) = function_scope + .labels + .insert(stmt.label.clone(), Rc::clone(&label_info)) + { + let label = old.borrow().name.clone(); + Err(ConversionError::MultipleLabelDefinition(label)) + } else { + Ok(Statement::Labeled(statement::StmtLabeled { + label: label_info, + statement: Box::new(self.process_statement(*stmt.statement)?), + })) + } + } else { + Err(ConversionError::LabelDefinitionOutsideFunction) + } + } + pub(crate) fn process_statement_goto( + &mut self, + stmt: ast::StmtGoto, + ) -> Result { + if let Some(function_scope) = &mut self.function_scope { + if let Some(label) = function_scope.labels.get(&stmt.label) { + Ok(Statement::Goto(statement::StmtGoto { + label: Rc::clone(label), + })) + } else { + Err(ConversionError::GotoInvalidLabel(stmt.label)) + } + } else { + Err(ConversionError::GotoOutsideFunction) + } } pub(crate) fn process_statement_compound( &mut self, stmt: ast::StmtCompound, ) -> Result { + self.begin_scope()?; + + let compound = statement::StmtCompound { + statements: stmt + .statements + .into_iter() + .map(|stmt| self.process_statement(stmt)) + .collect::, _>>()?, + }; + + self.end_scope()?; + Ok(Statement::Compound(compound)) } pub(crate) fn process_statement_if( &mut self, stmt: ast::StmtIf, ) -> Result { + let cond = self.process_expression(stmt.cond)?; + let then = self.process_statement(*stmt.then_statement)?; + let else_ = if let Some(stmt) = stmt.else_statement { + Some(Box::new(self.process_statement(*stmt)?)) + } else { + None + }; + + Ok(Statement::If(statement::StmtIf { + condition: cond, + then: Box::new(then), + else_, + })) } pub(crate) fn process_statement_switch( &mut self, stmt: ast::StmtSwitch, ) -> Result { + self.begin_switch_scope()?; + let value = self.process_expression(stmt.target)?; + let body = self.process_statement(*stmt.statement)?; + self.end_switch_scope()?; + + let Statement::Compound(body) = body else { + return Err(ConversionError::InvalidSwitchBody); + }; + + let mut cases: Vec = Vec::new(); + for s in body.statements.into_iter() { + match s { + Statement::_Case(c) => { + cases.push(StmtSwitchCase { + value: Some(c.value), + statements: vec![*c.statement], + }); + } + Statement::_Default(d) => { + cases.push(StmtSwitchCase { + value: None, + statements: vec![*d.statement], + }); + } + s => { + if let Some(last) = cases.last_mut() { + last.statements.push(s); + } else { + return Err(ConversionError::InvalidSwitchBody); + } + } + } + } + Ok(Statement::Switch(statement::StmtSwitch { value, cases })) } pub(crate) fn process_statement_case( &mut self, stmt: ast::StmtCase, ) -> Result { + let value = self.process_expression(stmt.value)?; + let statement = self.process_statement(*stmt.statement)?; + if self.nearest_switch_scope().is_none() { + return Err(ConversionError::InvalidCase); + } + + Ok(Statement::_Case(statement::StmtCase { + value, + statement: Box::new(statement), + })) } pub(crate) fn process_statement_default( &mut self, stmt: ast::StmtDefault, ) -> Result { + let statement = self.process_statement(*stmt.statement)?; + if let Some(scope) = self.nearest_switch_scope() { + if scope.default { + return Err(ConversionError::MultipleDefault); + } + } else { + return Err(ConversionError::InvalidDefault); + } + + Ok(Statement::_Default(statement::StmtDefault { + statement: Box::new(statement), + })) } pub(crate) fn process_statement_continue( &mut self, - stmt: ast::StmtContinue, + _stmt: ast::StmtContinue, ) -> Result { + if !self.can_continue() { + return Err(ConversionError::InvalidContinue); + } + + Ok(Statement::Continue) } pub(crate) fn process_statement_break( &mut self, - stmt: ast::StmtBreak, + _stmt: ast::StmtBreak, ) -> Result { + if !self.can_break() { + return Err(ConversionError::InvalidBreak); + } + + Ok(Statement::Break) } pub(crate) fn process_statement_while( &mut self, stmt: ast::StmtWhile, ) -> Result { + self.begin_loop_scope()?; + + let cond = self.process_expression(stmt.cond)?; + let body = self.process_statement(*stmt.statement)?; + + self.end_loop_scope()?; + + Ok(Statement::While(statement::StmtWhile { + condition: cond, + body: Box::new(body), + })) } pub(crate) fn process_statement_dowhile( &mut self, stmt: ast::StmtDoWhile, ) -> Result { + self.begin_loop_scope()?; + + let body = self.process_statement(*stmt.statement)?; + let cond = self.process_expression(stmt.cond)?; + + self.end_loop_scope()?; + + Ok(Statement::DoWhile(statement::StmtDoWhile { + body: Box::new(body), + condition: cond, + })) } pub(crate) fn process_statement_for( &mut self, stmt: ast::StmtFor, ) -> Result { - } - pub(crate) fn process_statement_goto( - &mut self, - stmt: ast::StmtGoto, - ) -> Result { + self.begin_loop_scope()?; + + let init = self.process_statement(*stmt.init)?; + let cond = self.process_expression(stmt.cond)?; + let next = if let Some(expr) = stmt.next { + Some(self.process_expression(expr)?) + } else { + None + }; + let body = self.process_statement(*stmt.statement)?; + + self.end_loop_scope()?; + + Ok(Statement::For(statement::StmtFor { + init: Box::new(init), + condition: cond, + next, + body: Box::new(body), + })) } pub(crate) fn process_statement_return( &mut self, stmt: ast::StmtReturn, ) -> Result { + if !self.can_return() { + return Err(ConversionError::InvalidReturn); + } + // @TODO type check + + let expr = if let Some(expr) = stmt.expr { + Some(self.process_expression(expr)?) + } else { + None + }; + Ok(Statement::Return(statement::StmtReturn { + expression: expr, + })) } pub(crate) fn process_statement_declaration( &mut self, @@ -342,9 +478,34 @@ impl Context { &mut self, stmt: ast::StmtFunctionDefinition, ) -> Result { + let base_type = match stmt.specs { + Some(specs) => self.process_decl_specs(specs.into_iter())?, + None => CVType::from_primitive(PrimitiveType::Void), + }; + let decl = self.process_declarator(stmt.decl, base_type)?; + let name = match decl.name { + Some(name) => name, + None => return Err(ConversionError::NoFunctionName), + }; + match decl.type_.type_ { + PrimitiveType::Function(func) => { + self.begin_function_scope(name.clone(), func.clone())?; + let body = self.process_statement(*stmt.body)?; + let scope = self.end_function_scope()?; + let statement = Statement::FunctionDefinition(statement::StmtFunctionDefinition { + name, + definition: func, + body: Box::new(body), + stack_size: scope.stack_size, + }); + Ok(statement) + } + _ => return Err(ConversionError::InvalidFunctionDefinition), + } } } +// for expressions impl Context { pub(crate) fn process_expression_identifier( &mut self, @@ -430,6 +591,14 @@ impl Context { &mut self, expr: ast::ExprConditional, ) -> Result { + let cond = self.process_expression(*expr.cond)?; + let then = self.process_expression(*expr.then_expr)?; + let else_ = self.process_expression(*expr.else_expr)?; + Ok(Expression::Conditional(expression::ExprConditional { + cond: Box::new(cond), + then_expr: Box::new(then), + else_expr: Box::new(else_), + })) } pub(crate) fn process_expression_unary( &mut self, @@ -445,27 +614,80 @@ impl Context { &mut self, expr: ast::ExprInitializerList, ) -> Result { + Ok(Expression::InitializerList( + expression::ExprInitializerList { + exprs: expr + .initializers + .into_iter() + .map(|expr| self.process_expression(expr)) + .collect::, _>>()?, + }, + )) } } +// for declarators impl Context { + pub(crate) fn process_specs( + &mut self, + mut specs: impl Iterator, + ) -> Result { + unimplemented!("process_specs") + } + pub(crate) fn process_decl_specs( + &mut self, + mut specs: impl Iterator, + ) -> Result { + unimplemented!("process_specs") + } pub(crate) fn process_declarator_identifier( &mut self, decl: ast::DeclIdentifier, base_type: CVType, ) -> Result { + Ok(CombinedDeclarator { + name: Some(decl.name), + type_: base_type, + }) } pub(crate) fn process_declarator_pointer( &mut self, decl: ast::DeclPointer, base_type: CVType, ) -> Result { + if let Some(decl) = decl.declarator { + let mut res = self.process_declarator(*decl, base_type)?; + res.type_ = CVType::from_primitive(PrimitiveType::Pointer(Box::new(res.type_))); + Ok(res) + } else { + Ok(CombinedDeclarator { + name: None, + type_: CVType::from_primitive(PrimitiveType::Pointer(Box::new(base_type))), + }) + } } pub(crate) fn process_declarator_array_fixed( &mut self, decl: ast::DeclArrayFixed, base_type: CVType, ) -> Result { + let size = self.process_expression(decl.size)?; + if let Some(decl) = decl.declarator { + let mut res = self.process_declarator(*decl, base_type)?; + res.type_ = CVType::from_primitive(PrimitiveType::Array(ArrayType { + type_: Box::new(res.type_), + size: size, + })); + Ok(res) + } else { + Ok(CombinedDeclarator { + name: None, + type_: CVType::from_primitive(PrimitiveType::Array(ArrayType { + type_: Box::new(base_type), + size: size, + })), + }) + } } pub(crate) fn process_declarator_array_unbounded( &mut self, @@ -482,13 +704,35 @@ impl Context { pub(crate) fn process_declarator_const( &mut self, decl: ast::DeclConst, - base_type: CVType, + mut base_type: CVType, ) -> Result { + if let Some(decl) = decl.declarator { + let mut res = self.process_declarator(*decl, base_type)?; + res.type_.const_ = true; + Ok(res) + } else { + base_type.const_ = true; + Ok(CombinedDeclarator { + name: None, + type_: base_type, + }) + } } pub(crate) fn process_declarator_volatile( &mut self, decl: ast::DeclVolatile, - base_type: CVType, + mut base_type: CVType, ) -> Result { + if let Some(decl) = decl.declarator { + let mut res = self.process_declarator(*decl, base_type)?; + res.type_.volatile = true; + Ok(res) + } else { + base_type.volatile = true; + Ok(CombinedDeclarator { + name: None, + type_: base_type, + }) + } } } diff --git a/src/ast2/error.rs b/src/ast2/error.rs index ff360d1..a70ae75 100644 --- a/src/ast2/error.rs +++ b/src/ast2/error.rs @@ -1 +1,21 @@ -pub enum ConversionError {} +#[derive(Debug, Clone)] +pub enum ConversionError { + InvalidCase, + InvalidContinue, + InvalidBreak, + /// switch body must be a compound statement '{' ... '}'. + /// switch body must start with `case` or `default`. + InvalidSwitchBody, + InvalidReturn, + InvalidDefault, + MultipleDefault, + + NoFunctionName, + InvalidFunctionDefinition, + + LabelDefinitionOutsideFunction, + MultipleLabelDefinition(String), + + GotoOutsideFunction, + GotoInvalidLabel(String), +} diff --git a/src/ast2/expression.rs b/src/ast2/expression.rs index 05ce0c5..a631245 100644 --- a/src/ast2/expression.rs +++ b/src/ast2/expression.rs @@ -1 +1,54 @@ -pub enum Expression {} +use crate::ast; + +use super::PrimitiveType; + +#[derive(Debug, Clone)] +pub enum Expression { + SizeofExpr(Box), + + Conditional(ExprConditional), + + Unary(ExprUnary), + Binary(ExprBinary), + InitializerList(ExprInitializerList), +} +impl Expression { + pub fn get_primitive_type(&self) -> Option { + match self { + Expression::SizeofExpr(_) => Some(PrimitiveType::UnsignedLong), + Expression::Conditional(_) => None, + Expression::Unary(_) => None, + Expression::Binary(_) => None, + Expression::InitializerList(_) => None, + } + } +} + +#[derive(Debug, Clone)] +pub struct ExprConditional { + pub cond: Box, + pub then_expr: Box, + pub else_expr: Box, +} + +pub type ExprUnaryOp = ast::ExprUnaryOperator; + +#[derive(Debug, Clone)] +pub struct ExprUnary { + pub op: ExprUnaryOp, + pub expr: Box, +} + +pub type ExprBinaryOp = ast::ExprBinaryOperator; + +#[derive(Debug, Clone)] +pub struct ExprBinary { + pub op: ast::ExprBinaryOperator, + pub lhs: Box, + pub rhs: Box, +} + +#[derive(Debug, Clone)] +pub struct ExprInitializerList { + pub exprs: Vec, +} diff --git a/src/ast2/label.rs b/src/ast2/label.rs new file mode 100644 index 0000000..2b9c3dd --- /dev/null +++ b/src/ast2/label.rs @@ -0,0 +1,4 @@ +#[derive(Debug, Clone)] +pub struct LabelInfo { + pub name: String, +} diff --git a/src/ast2/mod.rs b/src/ast2/mod.rs index feae52b..21b0588 100644 --- a/src/ast2/mod.rs +++ b/src/ast2/mod.rs @@ -2,13 +2,32 @@ mod context; mod declarator; mod error; mod expression; +mod label; mod scope; mod statement; mod typename; mod variable; +pub use statement::Statement; +pub use statement::StmtCompound; +pub use statement::StmtExpression; +pub use statement::StmtFor; +pub use statement::StmtFunctionDefinition; +pub use statement::StmtGoto; +pub use statement::StmtIf; +pub use statement::StmtLabeled; +pub use statement::StmtReturn; +pub use statement::StmtSwitch; +pub use statement::StmtSwitchCase; + +pub use expression::Expression; + +pub use label::LabelInfo; + pub use declarator::CombinedDeclarator; pub use error::ConversionError; -pub use expression::Expression; -pub use statement::Statement; +pub use typename::ArrayType; pub use typename::CVType; +pub use typename::FunctionType; +pub use typename::PrimitiveType; +pub use variable::VariableInfo; diff --git a/src/ast2/scope.rs b/src/ast2/scope.rs index e69de29..31bc397 100644 --- a/src/ast2/scope.rs +++ b/src/ast2/scope.rs @@ -0,0 +1,63 @@ +use std::{cell::RefCell, collections::HashMap, rc::Rc}; + +use super::{FunctionType, LabelInfo}; + +#[derive(Debug, Clone)] +pub enum Scope { + Switch(SwitchScope), + Loop(LoopScope), + Block(BlockScope), + Variable(VariableScope), +} + +/// for switch statement, `break` and `default` +#[derive(Debug, Clone)] +pub struct SwitchScope { + pub id: usize, + // is `default` defined + pub default: bool, +} + +/// for any loop statement, `break` and `continue` +#[derive(Debug, Clone)] +pub struct LoopScope { + pub id: usize, +} + +#[derive(Debug, Clone)] +pub struct BlockScope { + pub id: usize, +} + +#[derive(Debug, Clone)] +pub struct VariableScope { + pub name: String, +} + +#[derive(Clone)] +pub struct FunctionScope { + pub name: String, + pub type_: FunctionType, + pub stack_size: usize, + pub labels: HashMap>>, +} +impl FunctionScope { + pub fn new(name: String, type_: FunctionType) -> Self { + FunctionScope { + name, + type_, + stack_size: 0, + labels: HashMap::new(), + } + } +} + +#[derive(Debug, Clone)] +pub struct GlobalScope { + pub stack_size: usize, +} +impl GlobalScope { + pub fn new() -> Self { + GlobalScope { stack_size: 0 } + } +} diff --git a/src/ast2/statement.rs b/src/ast2/statement.rs index 818f600..0fc21d4 100644 --- a/src/ast2/statement.rs +++ b/src/ast2/statement.rs @@ -1 +1,106 @@ -pub enum Statement {} +use std::{cell::RefCell, rc::Rc}; + +use super::{Expression, FunctionType, LabelInfo}; + +#[derive(Debug, Clone)] +pub enum Statement { + None, + Expression(StmtExpression), + Labeled(StmtLabeled), + Goto(StmtGoto), + Compound(StmtCompound), + If(StmtIf), + Switch(StmtSwitch), + /// for internal use; this variant will not be visible to end-users + _Case(StmtCase), + /// for internal use; this variant will not be visible to end-users + _Default(StmtDefault), + Continue, + Break, + Return(StmtReturn), + For(StmtFor), + While(StmtWhile), + DoWhile(StmtDoWhile), + FunctionDefinition(StmtFunctionDefinition), +} + +#[derive(Debug, Clone)] +pub struct StmtExpression { + pub expression: Expression, +} + +#[derive(Debug, Clone)] +pub struct StmtLabeled { + pub label: Rc>, + pub statement: Box, +} +#[derive(Debug, Clone)] +pub struct StmtGoto { + pub label: Rc>, +} + +#[derive(Debug, Clone)] +pub struct StmtCompound { + pub statements: Vec, +} + +#[derive(Debug, Clone)] +pub struct StmtIf { + pub condition: Expression, + pub then: Box, + pub else_: Option>, +} + +#[derive(Debug, Clone)] +pub struct StmtSwitch { + pub value: Expression, + pub cases: Vec, +} +#[derive(Debug, Clone)] +pub struct StmtSwitchCase { + /// `None` for `default` + pub value: Option, + pub statements: Vec, +} +#[derive(Debug, Clone)] +pub struct StmtCase { + pub value: Expression, + pub statement: Box, +} +#[derive(Debug, Clone)] +pub struct StmtDefault { + pub statement: Box, +} + +#[derive(Debug, Clone)] +pub struct StmtReturn { + pub expression: Option, +} + +#[derive(Debug, Clone)] +pub struct StmtFor { + pub init: Box, + pub condition: Expression, + pub next: Option, + pub body: Box, +} + +#[derive(Debug, Clone)] +pub struct StmtWhile { + pub condition: Expression, + pub body: Box, +} + +#[derive(Debug, Clone)] +pub struct StmtDoWhile { + pub body: Box, + pub condition: Expression, +} + +#[derive(Debug, Clone)] +pub struct StmtFunctionDefinition { + pub name: String, + pub definition: FunctionType, + pub body: Box, + pub stack_size: usize, +} diff --git a/src/ast2/typename.rs b/src/ast2/typename.rs index cf12954..0fc4f89 100644 --- a/src/ast2/typename.rs +++ b/src/ast2/typename.rs @@ -31,6 +31,7 @@ pub struct FunctionType { // maybe no need CV qualifier for return type? pub return_type: Box, pub args: Vec, + pub variadic: bool, } #[derive(Debug, Clone)] @@ -39,3 +40,30 @@ pub struct CVType { pub const_: bool, pub volatile: bool, } +impl CVType { + pub fn from_primitive(type_: PrimitiveType) -> Self { + Self { + type_, + const_: false, + volatile: false, + } + } + + pub fn into_pointer(self) -> Self { + Self { + type_: PrimitiveType::Pointer(Box::new(self)), + const_: false, + volatile: false, + } + } + pub fn into_array(self, size: usize) -> Self { + Self { + type_: PrimitiveType::Array(ArrayType { + type_: Box::new(self), + size, + }), + const_: false, + volatile: false, + } + } +} From d19930c5c77ee10c10d84de675b7ab2ddcc2180f Mon Sep 17 00:00:00 2001 From: Taehwan Kim Date: Tue, 29 Oct 2024 23:41:50 +0900 Subject: [PATCH 04/10] expressions, functions and variables --- src/ast2/context.rs | 559 ++++++++++++++++++++++++++++++++++------- src/ast2/declarator.rs | 2 +- src/ast2/error.rs | 24 +- src/ast2/expression.rs | 55 +++- src/ast2/mod.rs | 22 +- src/ast2/scope.rs | 23 +- src/ast2/statement.rs | 13 +- src/ast2/typename.rs | 98 ++++++++ src/ast2/variable.rs | 41 +++ 9 files changed, 711 insertions(+), 126 deletions(-) diff --git a/src/ast2/context.rs b/src/ast2/context.rs index 33a4716..268c59b 100644 --- a/src/ast2/context.rs +++ b/src/ast2/context.rs @@ -3,18 +3,23 @@ use std::rc::Rc; use super::expression; use super::statement; +use super::Address; use super::ArrayType; use super::CVType; use super::CombinedDeclarator; -use super::ConversionError; +use super::CompileError; use super::Expression; use super::FunctionType; use super::PrimitiveType; use super::Statement; use super::StmtSwitchCase; +use super::StorageQualifier; +use super::VariableInfo; use crate::ast; +use crate::ast2::StmtVariableDeclaration; use super::scope::BlockScope; +use super::scope::FunctionDefinition; use super::scope::FunctionScope; use super::scope::GlobalScope; use super::scope::LoopScope; @@ -47,7 +52,7 @@ impl Context { self.scope_counter += 1; self.scope_counter } - fn begin_switch_scope(&mut self) -> Result<(), ConversionError> { + fn begin_switch_scope(&mut self) -> Result<(), CompileError> { let scope = SwitchScope { id: self.generate_scope_id(), default: false, @@ -64,30 +69,31 @@ impl Context { } None } - fn end_switch_scope(&mut self) -> Result { + fn end_switch_scope(&mut self) -> Result { + // @TODO pop every variable scope until switch scope unimplemented!("end_switch_scope") - // must pop every variable scope until switch scope } - fn begin_loop_scope(&mut self) -> Result<(), ConversionError> { + fn begin_loop_scope(&mut self) -> Result<(), CompileError> { let scope = LoopScope { id: self.generate_scope_id(), }; self.scopes.push(Scope::Loop(scope)); Ok(()) } - fn end_loop_scope(&mut self) -> Result { + fn end_loop_scope(&mut self) -> Result { + // @TODO pop every variable scope until loop scope unimplemented!("end_loop_scope") - // must pop every variable scope until loop scope } - fn begin_scope(&mut self) -> Result<(), ConversionError> { + fn begin_scope(&mut self) -> Result<(), CompileError> { let scope = BlockScope { id: self.generate_scope_id(), }; self.scopes.push(Scope::Block(scope)); Ok(()) } - fn end_scope(&mut self) -> Result { + fn end_scope(&mut self) -> Result { + // @TODO pop every variable scope until block scope unimplemented!("end_scope") } @@ -95,15 +101,45 @@ impl Context { &mut self, name: String, type_: FunctionType, - ) -> Result<(), ConversionError> { + ) -> Result<(), CompileError> { unimplemented!("begin_function_scope") } - fn end_function_scope(&mut self) -> Result { + fn end_function_scope(&mut self) -> Result { + // @TODO pop every variable scope until function scope unimplemented!("end_function_scope") } - fn begin_variable_scope(&mut self, name: String) -> Result<(), ConversionError> { - unimplemented!("begin_variable_scope") + fn begin_variable_scope( + &mut self, + name: String, + type_: CVType, + ) -> Result { + // search for `name` in current scope + for scope in self.scopes.iter().rev() { + match scope { + Scope::Variable(scope) => { + if scope.name == name { + return Err(CompileError::MultipleVariableDefinition(name)); + } + } + _ => break, + } + } + + let size = self.type_sizeof(&type_.type_)?; + let align = self.type_alignof(&type_.type_)?; + let offset = self.function_scope.as_mut().unwrap().pool.add(size, align); + let varinfo = VariableInfo { + name: name.clone(), + address: Address::Local(offset), + cv_type: type_, + }; + let scope = VariableScope { + name, + info: varinfo.clone(), + }; + self.scopes.push(Scope::Variable(scope)); + Ok(varinfo) } fn can_continue(&self) -> bool { @@ -131,7 +167,7 @@ impl Context { pub fn process_statement( &mut self, statement: ast::Statement, - ) -> Result { + ) -> Result { match statement { ast::Statement::Null(stmt) => self.process_statement_null(stmt), ast::Statement::Expression(stmt) => self.process_statement_expression(stmt), @@ -158,7 +194,7 @@ impl Context { pub fn process_expression( &mut self, expression: ast::Expression, - ) -> Result { + ) -> Result { match expression { ast::Expression::Identifier(expr) => self.process_expression_identifier(expr), ast::Expression::ConstantCharacter(expr) => { @@ -193,7 +229,7 @@ impl Context { &mut self, declarator: ast::Declarator, base_type: CVType, - ) -> Result { + ) -> Result { match declarator { ast::Declarator::Identifier(decl) => { self.process_declarator_identifier(decl, base_type) @@ -217,13 +253,13 @@ impl Context { pub(crate) fn process_statement_null( &mut self, _stmt: ast::StmtNull, - ) -> Result { + ) -> Result { Ok(Statement::None) } pub(crate) fn process_statement_expression( &mut self, stmt: ast::StmtExpression, - ) -> Result { + ) -> Result { Ok(Statement::Expression(statement::StmtExpression { expression: self.process_expression(stmt.expression)?, })) @@ -231,7 +267,7 @@ impl Context { pub(crate) fn process_statement_labeled( &mut self, stmt: ast::StmtLabeled, - ) -> Result { + ) -> Result { if let Some(function_scope) = &mut self.function_scope { let label_info = LabelInfo { name: stmt.label.clone(), @@ -242,7 +278,7 @@ impl Context { .insert(stmt.label.clone(), Rc::clone(&label_info)) { let label = old.borrow().name.clone(); - Err(ConversionError::MultipleLabelDefinition(label)) + Err(CompileError::MultipleLabelDefinition(label)) } else { Ok(Statement::Labeled(statement::StmtLabeled { label: label_info, @@ -250,29 +286,29 @@ impl Context { })) } } else { - Err(ConversionError::LabelDefinitionOutsideFunction) + Err(CompileError::LabelDefinitionOutsideFunction) } } pub(crate) fn process_statement_goto( &mut self, stmt: ast::StmtGoto, - ) -> Result { + ) -> Result { if let Some(function_scope) = &mut self.function_scope { if let Some(label) = function_scope.labels.get(&stmt.label) { Ok(Statement::Goto(statement::StmtGoto { label: Rc::clone(label), })) } else { - Err(ConversionError::GotoInvalidLabel(stmt.label)) + Err(CompileError::GotoInvalidLabel(stmt.label)) } } else { - Err(ConversionError::GotoOutsideFunction) + Err(CompileError::GotoOutsideFunction) } } pub(crate) fn process_statement_compound( &mut self, stmt: ast::StmtCompound, - ) -> Result { + ) -> Result { self.begin_scope()?; let compound = statement::StmtCompound { @@ -289,7 +325,7 @@ impl Context { pub(crate) fn process_statement_if( &mut self, stmt: ast::StmtIf, - ) -> Result { + ) -> Result { let cond = self.process_expression(stmt.cond)?; let then = self.process_statement(*stmt.then_statement)?; let else_ = if let Some(stmt) = stmt.else_statement { @@ -307,14 +343,14 @@ impl Context { pub(crate) fn process_statement_switch( &mut self, stmt: ast::StmtSwitch, - ) -> Result { + ) -> Result { self.begin_switch_scope()?; let value = self.process_expression(stmt.target)?; let body = self.process_statement(*stmt.statement)?; self.end_switch_scope()?; let Statement::Compound(body) = body else { - return Err(ConversionError::InvalidSwitchBody); + return Err(CompileError::InvalidSwitchBody); }; let mut cases: Vec = Vec::new(); @@ -336,7 +372,7 @@ impl Context { if let Some(last) = cases.last_mut() { last.statements.push(s); } else { - return Err(ConversionError::InvalidSwitchBody); + return Err(CompileError::InvalidSwitchBody); } } } @@ -346,11 +382,11 @@ impl Context { pub(crate) fn process_statement_case( &mut self, stmt: ast::StmtCase, - ) -> Result { + ) -> Result { let value = self.process_expression(stmt.value)?; let statement = self.process_statement(*stmt.statement)?; if self.nearest_switch_scope().is_none() { - return Err(ConversionError::InvalidCase); + return Err(CompileError::InvalidCase); } Ok(Statement::_Case(statement::StmtCase { @@ -361,14 +397,14 @@ impl Context { pub(crate) fn process_statement_default( &mut self, stmt: ast::StmtDefault, - ) -> Result { + ) -> Result { let statement = self.process_statement(*stmt.statement)?; if let Some(scope) = self.nearest_switch_scope() { if scope.default { - return Err(ConversionError::MultipleDefault); + return Err(CompileError::MultipleDefault); } } else { - return Err(ConversionError::InvalidDefault); + return Err(CompileError::InvalidDefault); } Ok(Statement::_Default(statement::StmtDefault { @@ -378,9 +414,9 @@ impl Context { pub(crate) fn process_statement_continue( &mut self, _stmt: ast::StmtContinue, - ) -> Result { + ) -> Result { if !self.can_continue() { - return Err(ConversionError::InvalidContinue); + return Err(CompileError::InvalidContinue); } Ok(Statement::Continue) @@ -388,9 +424,9 @@ impl Context { pub(crate) fn process_statement_break( &mut self, _stmt: ast::StmtBreak, - ) -> Result { + ) -> Result { if !self.can_break() { - return Err(ConversionError::InvalidBreak); + return Err(CompileError::InvalidBreak); } Ok(Statement::Break) @@ -398,7 +434,7 @@ impl Context { pub(crate) fn process_statement_while( &mut self, stmt: ast::StmtWhile, - ) -> Result { + ) -> Result { self.begin_loop_scope()?; let cond = self.process_expression(stmt.cond)?; @@ -414,7 +450,7 @@ impl Context { pub(crate) fn process_statement_dowhile( &mut self, stmt: ast::StmtDoWhile, - ) -> Result { + ) -> Result { self.begin_loop_scope()?; let body = self.process_statement(*stmt.statement)?; @@ -430,7 +466,7 @@ impl Context { pub(crate) fn process_statement_for( &mut self, stmt: ast::StmtFor, - ) -> Result { + ) -> Result { self.begin_loop_scope()?; let init = self.process_statement(*stmt.init)?; @@ -454,9 +490,9 @@ impl Context { pub(crate) fn process_statement_return( &mut self, stmt: ast::StmtReturn, - ) -> Result { + ) -> Result { if !self.can_return() { - return Err(ConversionError::InvalidReturn); + return Err(CompileError::InvalidReturn); } // @TODO type check @@ -472,125 +508,370 @@ impl Context { pub(crate) fn process_statement_declaration( &mut self, stmt: ast::StmtDeclaration, - ) -> Result { + ) -> Result { + // @TODO storage_qualifier check + // currently ignore all storage qualifiers + let (storage_qualifier, base_type) = self.process_decl_specs(stmt.specs.into_iter())?; + + match stmt.inits { + Some(decl_inits) => { + let mut pairs = Vec::new(); + // - variable definition + // @TODO + // - function declaration + // - typedef + for init in decl_inits.into_iter() { + let init_type = self.process_declarator(*init.declarator, base_type.clone())?; + let Some(name) = init_type.name else { + return Err(CompileError::DeclarationWithoutName); + }; + + match &init_type.cv_type.type_ { + // this is function declaration without body + PrimitiveType::Function(_func) => { + if self.function_scope.is_some() { + return Err(CompileError::NestedFunctionDefinition); + } + + if let Some(old) = self.global_scope.variables.insert( + name.clone(), + VariableInfo { + name, + address: Address::Function(self.global_scope.functions.len()), + cv_type: init_type.cv_type.clone(), + }, + ) { + return Err(CompileError::MultipleVariableDefinition(old.name)); + } + // body will be `None`, and be `Some` when function definition is found + self.global_scope + .functions + .push(Rc::new(RefCell::new(None))); + } + _ => { + if self.function_scope.is_some() { + let varinfo = self.begin_variable_scope( + name.clone(), + init_type.cv_type.clone(), + )?; + if let Some(init) = init.initializer { + let init = self.process_expression(init)?; + pairs.push((varinfo, init)); + } + } else { + if self.global_scope.variables.contains_key(&name) { + return Err(CompileError::MultipleVariableDefinition(name)); + } + + let size = self.type_sizeof(&init_type.cv_type.type_)?; + let align = self.type_alignof(&init_type.cv_type.type_)?; + let offset = self.global_scope.pool.add(size, align); + let varinfo = VariableInfo { + name: name.clone(), + address: Address::Global(offset), + cv_type: init_type.cv_type, + }; + self.global_scope.variables.insert(name, varinfo.clone()); + if let Some(init) = init.initializer { + let init = self.process_expression(init)?; + pairs.push((varinfo, init)); + } else { + // @TODO + // default value since this variable is in static storage + } + } + } + } + } + Ok(Statement::VariableDeclaration(StmtVariableDeclaration { + pairs, + })) + } + None => { + // struct, union, enum type definition + // or just ill-formed declaration (but it's not an error) + unreachable!("process_statement_declaration: struct, union, enum definition") + } + } } pub(crate) fn process_statement_functiondefinition( &mut self, stmt: ast::StmtFunctionDefinition, - ) -> Result { - let base_type = match stmt.specs { + ) -> Result { + if self.function_scope.is_some() { + return Err(CompileError::NestedFunctionDefinition); + } + + let (storage_qualifier, base_type) = match stmt.specs { Some(specs) => self.process_decl_specs(specs.into_iter())?, - None => CVType::from_primitive(PrimitiveType::Void), + None => ( + StorageQualifier::new(), + CVType::from_primitive(PrimitiveType::Void), + ), }; + // @TODO storage_qualifier check let decl = self.process_declarator(stmt.decl, base_type)?; let name = match decl.name { Some(name) => name, - None => return Err(ConversionError::NoFunctionName), + None => return Err(CompileError::NoFunctionName), }; - match decl.type_.type_ { + + let (function_definition, function_type) = match decl.cv_type.type_ { PrimitiveType::Function(func) => { self.begin_function_scope(name.clone(), func.clone())?; let body = self.process_statement(*stmt.body)?; let scope = self.end_function_scope()?; - let statement = Statement::FunctionDefinition(statement::StmtFunctionDefinition { - name, - definition: func, - body: Box::new(body), - stack_size: scope.stack_size, - }); - Ok(statement) + ( + FunctionDefinition { + body: Box::new(body), + stack_size: scope.pool.max_size, + }, + func, + ) + } + _ => return Err(CompileError::InvalidFunctionDefinition), + }; + + // check if + // - there is other variable with same name + // - there is function declaration with same signature + + if let Some(varinfo) = self.global_scope.variables.get(&name) { + match &varinfo.cv_type.type_ { + PrimitiveType::Function(func) => { + if func != &function_type { + return Err(CompileError::FunctionDifferentSignature(name)); + } + } + _ => return Err(CompileError::MultipleVariableDefinition(name)), + } + let Address::Function(address) = varinfo.address else { + unreachable!(); + }; + + if self.global_scope.functions[address].borrow().is_some() { + return Err(CompileError::MultipleFunctionDefinition(name)); } - _ => return Err(ConversionError::InvalidFunctionDefinition), + self.global_scope.functions[address].replace(Some(function_definition)); + } else { + let function_offset = self.global_scope.functions.len(); + self.global_scope + .functions + .push(Rc::new(RefCell::new(Some(function_definition)))); + + let varinfo = VariableInfo { + name: name.clone(), + address: Address::Function(function_offset), + cv_type: CVType::from_primitive(PrimitiveType::Function(function_type)), + }; + self.global_scope.variables.insert(name, varinfo); } + + Ok(Statement::None) } } // for expressions impl Context { + pub fn expression_type(&self, expr: &Expression) -> CVType { + match expr { + Expression::Variable(var) => var.cv_type.clone(), + Expression::I8(_) => CVType::from_primitive(PrimitiveType::Int8), + Expression::I16(_) => CVType::from_primitive(PrimitiveType::Int16), + Expression::I32(_) => CVType::from_primitive(PrimitiveType::Int32), + Expression::I64(_) => CVType::from_primitive(PrimitiveType::Int64), + Expression::U8(_) => CVType::from_primitive(PrimitiveType::UInt8), + Expression::U16(_) => CVType::from_primitive(PrimitiveType::UInt16), + Expression::U32(_) => CVType::from_primitive(PrimitiveType::UInt32), + Expression::U64(_) => CVType::from_primitive(PrimitiveType::UInt64), + Expression::F32(_) => CVType::from_primitive(PrimitiveType::Float32), + Expression::F64(_) => CVType::from_primitive(PrimitiveType::Float64), + Expression::String(_) => { + CVType::from_primitive(PrimitiveType::Pointer(Box::new(CVType { + type_: PrimitiveType::Int8, + const_: true, + volatile: false, + }))) + } + Expression::Cast(expr) => expr.type_.clone(), + Expression::Arrow(expr) => unimplemented!("expression_type Arrow"), + Expression::Bracket(expr) => unimplemented!("expression_type Bracket"), + Expression::Conditional(expr) => unimplemented!("expression_type Conditional"), + Expression::InitializerList(expr) => unimplemented!("expression_type InitializerList"), + Expression::Paren(expr) => unimplemented!("expression_type Paren"), + Expression::Binary(expr) => unimplemented!("expression_type Binary"), + Expression::Unary(expr) => unimplemented!("expression_type Unary"), + } + } pub(crate) fn process_expression_identifier( &mut self, expr: ast::ExprIdentifier, - ) -> Result { + ) -> Result { + if self.function_scope.is_some() { + for scope in self.scopes.iter().rev() { + match scope { + Scope::Variable(scope) => { + if scope.name == expr.name { + return Ok(Expression::Variable(scope.info.clone())); + } + } + _ => {} + } + } + } + if let Some(varinfo) = self.global_scope.variables.get(&expr.name) { + return Ok(Expression::Variable(varinfo.clone())); + } + return Err(CompileError::VariableNotFound(expr.name)); } pub(crate) fn process_expression_constantcharacter( &mut self, expr: ast::ExprConstantCharacter, - ) -> Result { + ) -> Result { + Ok(Expression::I8(expr.value)) } pub(crate) fn process_expression_constantinteger( &mut self, expr: ast::ExprConstantInteger, - ) -> Result { + ) -> Result { + Ok(Expression::I32(expr.value)) } pub(crate) fn process_expression_constantunsignedinteger( &mut self, expr: ast::ExprConstantUnsignedInteger, - ) -> Result { + ) -> Result { + Ok(Expression::U32(expr.value)) } pub(crate) fn process_expression_constantlong( &mut self, expr: ast::ExprConstantLong, - ) -> Result { + ) -> Result { + Ok(Expression::I64(expr.value)) } pub(crate) fn process_expression_constantunsignedlong( &mut self, expr: ast::ExprConstantUnsignedLong, - ) -> Result { + ) -> Result { + Ok(Expression::U64(expr.value)) } pub(crate) fn process_expression_constantfloat( &mut self, expr: ast::ExprConstantFloat, - ) -> Result { + ) -> Result { + Ok(Expression::F32(expr.value)) } pub(crate) fn process_expression_constantdouble( &mut self, expr: ast::ExprConstantDouble, - ) -> Result { + ) -> Result { + Ok(Expression::F64(expr.value)) } pub(crate) fn process_expression_string( &mut self, expr: ast::ExprString, - ) -> Result { + ) -> Result { + Ok(Expression::String(expr.value)) } pub(crate) fn process_expression_member( &mut self, expr: ast::ExprMember, - ) -> Result { + ) -> Result { + let src = self.process_expression(*expr.src)?; + match self.expression_type(&src).type_ { + PrimitiveType::Struct | PrimitiveType::Union => {} + _ => return Err(CompileError::MemberAccessOnNonStructOrUnion), + } + unreachable!("process_expression_member") } pub(crate) fn process_expression_arrow( &mut self, expr: ast::ExprArrow, - ) -> Result { + ) -> Result { + let src = self.process_expression(*expr.src)?; + match self.expression_type(&src).type_ { + PrimitiveType::Pointer(_) => {} + _ => return Err(CompileError::ArrowOnNonPointer), + } + + Ok(Expression::Arrow(expression::ExprArrow { + src: Box::new(src), + member: expr.member, + })) } pub(crate) fn process_expression_bracket( &mut self, expr: ast::ExprBracket, - ) -> Result { + ) -> Result { + let src = self.process_expression(*expr.src)?; + match self.expression_type(&src).type_ { + PrimitiveType::Array(_) | PrimitiveType::Pointer(_) => {} + _ => return Err(CompileError::BracketOnNonArrayOrPointer), + } + let index = self.process_expression(*expr.index)?; + if !self.expression_type(&index).type_.is_integer() { + return Err(CompileError::BracketIndexNotInteger); + } + + Ok(Expression::Bracket(expression::ExprBracket { + src: Box::new(src), + index: Box::new(index), + })) } pub(crate) fn process_expression_paren( &mut self, expr: ast::ExprParen, - ) -> Result { + ) -> Result { + // @TODO callable check + Ok(Expression::Paren(expression::ExprParen { + src: Box::new(self.process_expression(*expr.src)?), + args: expr + .args + .into_iter() + .map(|expr| self.process_expression(expr)) + .collect::, _>>()?, + })) } pub(crate) fn process_expression_cast( &mut self, expr: ast::ExprCast, - ) -> Result { + ) -> Result { + let base_type = self.process_specs(expr.typename.specs.into_iter())?; + let type_to = if let Some(decl) = expr.typename.declarator { + let decl = self.process_declarator(*decl, base_type)?; + decl.cv_type + } else { + base_type + }; + // @TODO check castable + Ok(Expression::Cast(expression::ExprCast { + expr: Box::new(self.process_expression(*expr.src)?), + type_: type_to, + })) } pub(crate) fn process_expression_sizeoftype( &mut self, expr: ast::ExprSizeOfType, - ) -> Result { + ) -> Result { + let base_type = self.process_specs(expr.typename.specs.into_iter())?; + let typename = if let Some(decl) = expr.typename.declarator { + self.process_declarator(*decl, base_type)?.cv_type + } else { + base_type + }; + Ok(Expression::U64(self.type_sizeof(&typename.type_)? as u64)) } pub(crate) fn process_expression_sizeofexpr( &mut self, expr: ast::ExprSizeOfExpr, - ) -> Result { + ) -> Result { + let expr = self.process_expression(*expr.expr)?; + let typename = self.expression_type(&expr); + Ok(Expression::U64(self.type_sizeof(&typename.type_)? as u64)) } pub(crate) fn process_expression_conditional( &mut self, expr: ast::ExprConditional, - ) -> Result { + ) -> Result { let cond = self.process_expression(*expr.cond)?; let then = self.process_expression(*expr.then_expr)?; let else_ = self.process_expression(*expr.else_expr)?; @@ -603,17 +884,29 @@ impl Context { pub(crate) fn process_expression_unary( &mut self, expr: ast::ExprUnary, - ) -> Result { + ) -> Result { + let src = self.process_expression(*expr.src)?; + Ok(Expression::Unary(expression::ExprUnary { + op: expr.op, + expr: Box::new(src), + })) } pub(crate) fn process_expression_binary( &mut self, expr: ast::ExprBinary, - ) -> Result { + ) -> Result { + let lhs = self.process_expression(*expr.lhs)?; + let rhs = self.process_expression(*expr.rhs)?; + Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })) } pub(crate) fn process_expression_initializerlist( &mut self, expr: ast::ExprInitializerList, - ) -> Result { + ) -> Result { Ok(Expression::InitializerList( expression::ExprInitializerList { exprs: expr @@ -628,41 +921,76 @@ impl Context { // for declarators impl Context { + pub fn type_sizeof(&self, typename: &PrimitiveType) -> Result { + Ok(match typename { + PrimitiveType::Void => return Err(CompileError::SizeofIncompleteType), + PrimitiveType::UInt8 | PrimitiveType::Int8 => 1, + PrimitiveType::UInt16 | PrimitiveType::Int16 => 2, + PrimitiveType::UInt32 | PrimitiveType::Int32 | PrimitiveType::Float32 => 4, + PrimitiveType::UInt64 | PrimitiveType::Int64 | PrimitiveType::Float64 => 8, + PrimitiveType::Pointer(_) => 8, + PrimitiveType::Array(ArrayType { type_, size }) => { + self.type_sizeof(&type_.type_)? * (*size) + } + PrimitiveType::Function(_) => return Err(CompileError::SizeofIncompleteType), + PrimitiveType::Struct | PrimitiveType::Union | PrimitiveType::Enum => { + unreachable!("size_of for struct/union/enum") + } + }) + } + pub fn type_alignof(&self, typename: &PrimitiveType) -> Result { + Ok(match typename { + PrimitiveType::Void => return Err(CompileError::SizeofIncompleteType), + PrimitiveType::UInt8 | PrimitiveType::Int8 => 1, + PrimitiveType::UInt16 | PrimitiveType::Int16 => 2, + PrimitiveType::UInt32 | PrimitiveType::Int32 | PrimitiveType::Float32 => 4, + PrimitiveType::UInt64 | PrimitiveType::Int64 | PrimitiveType::Float64 => 8, + PrimitiveType::Pointer(_) => 8, + PrimitiveType::Array(ArrayType { type_, size: _ }) => { + self.type_alignof(&type_.type_)? + } + PrimitiveType::Function(_) => return Err(CompileError::SizeofIncompleteType), + PrimitiveType::Struct | PrimitiveType::Union | PrimitiveType::Enum => { + unreachable!("size_of for struct/union/enum") + } + }) + } + pub(crate) fn process_specs( &mut self, mut specs: impl Iterator, - ) -> Result { + ) -> Result { unimplemented!("process_specs") } pub(crate) fn process_decl_specs( &mut self, mut specs: impl Iterator, - ) -> Result { + ) -> Result<(StorageQualifier, CVType), CompileError> { unimplemented!("process_specs") } pub(crate) fn process_declarator_identifier( &mut self, decl: ast::DeclIdentifier, base_type: CVType, - ) -> Result { + ) -> Result { Ok(CombinedDeclarator { name: Some(decl.name), - type_: base_type, + cv_type: base_type, }) } pub(crate) fn process_declarator_pointer( &mut self, decl: ast::DeclPointer, base_type: CVType, - ) -> Result { + ) -> Result { if let Some(decl) = decl.declarator { let mut res = self.process_declarator(*decl, base_type)?; - res.type_ = CVType::from_primitive(PrimitiveType::Pointer(Box::new(res.type_))); + res.cv_type = CVType::from_primitive(PrimitiveType::Pointer(Box::new(res.cv_type))); Ok(res) } else { Ok(CombinedDeclarator { name: None, - type_: CVType::from_primitive(PrimitiveType::Pointer(Box::new(base_type))), + cv_type: CVType::from_primitive(PrimitiveType::Pointer(Box::new(base_type))), }) } } @@ -670,19 +998,54 @@ impl Context { &mut self, decl: ast::DeclArrayFixed, base_type: CVType, - ) -> Result { + ) -> Result { let size = self.process_expression(decl.size)?; + let size = match size { + Expression::I8(v) => { + if v < 0 { + return Err(CompileError::NegativeArraySize); + } else { + v as usize + } + } + Expression::I16(v) => { + if v < 0 { + return Err(CompileError::NegativeArraySize); + } else { + v as usize + } + } + Expression::I32(v) => { + if v < 0 { + return Err(CompileError::NegativeArraySize); + } else { + v as usize + } + } + Expression::I64(v) => { + if v < 0 { + return Err(CompileError::NegativeArraySize); + } else { + v as usize + } + } + Expression::U8(v) => v as usize, + Expression::U16(v) => v as usize, + Expression::U32(v) => v as usize, + Expression::U64(v) => v as usize, + _ => return Err(CompileError::ArraySizeNotInteger), + }; if let Some(decl) = decl.declarator { let mut res = self.process_declarator(*decl, base_type)?; - res.type_ = CVType::from_primitive(PrimitiveType::Array(ArrayType { - type_: Box::new(res.type_), + res.cv_type = CVType::from_primitive(PrimitiveType::Array(ArrayType { + type_: Box::new(res.cv_type), size: size, })); Ok(res) } else { Ok(CombinedDeclarator { name: None, - type_: CVType::from_primitive(PrimitiveType::Array(ArrayType { + cv_type: CVType::from_primitive(PrimitiveType::Array(ArrayType { type_: Box::new(base_type), size: size, })), @@ -693,28 +1056,32 @@ impl Context { &mut self, decl: ast::DeclArrayUnbounded, base_type: CVType, - ) -> Result { + ) -> Result { } pub(crate) fn process_declarator_function( &mut self, decl: ast::DeclFunction, base_type: CVType, - ) -> Result { + ) -> Result { + if let Some(decl) = decl.declarator { + let res = self.process_declarator(*decl, base_type)?; + } else { + } } pub(crate) fn process_declarator_const( &mut self, decl: ast::DeclConst, mut base_type: CVType, - ) -> Result { + ) -> Result { if let Some(decl) = decl.declarator { let mut res = self.process_declarator(*decl, base_type)?; - res.type_.const_ = true; + res.cv_type.const_ = true; Ok(res) } else { base_type.const_ = true; Ok(CombinedDeclarator { name: None, - type_: base_type, + cv_type: base_type, }) } } @@ -722,16 +1089,16 @@ impl Context { &mut self, decl: ast::DeclVolatile, mut base_type: CVType, - ) -> Result { + ) -> Result { if let Some(decl) = decl.declarator { let mut res = self.process_declarator(*decl, base_type)?; - res.type_.volatile = true; + res.cv_type.volatile = true; Ok(res) } else { base_type.volatile = true; Ok(CombinedDeclarator { name: None, - type_: base_type, + cv_type: base_type, }) } } diff --git a/src/ast2/declarator.rs b/src/ast2/declarator.rs index 531e74d..88cdef7 100644 --- a/src/ast2/declarator.rs +++ b/src/ast2/declarator.rs @@ -4,5 +4,5 @@ use super::CVType; pub struct CombinedDeclarator { /// variable name, for direct declarator pub name: Option, - pub type_: CVType, + pub cv_type: CVType, } diff --git a/src/ast2/error.rs b/src/ast2/error.rs index a70ae75..c449f9c 100644 --- a/src/ast2/error.rs +++ b/src/ast2/error.rs @@ -1,5 +1,5 @@ #[derive(Debug, Clone)] -pub enum ConversionError { +pub enum CompileError { InvalidCase, InvalidContinue, InvalidBreak, @@ -18,4 +18,26 @@ pub enum ConversionError { GotoOutsideFunction, GotoInvalidLabel(String), + + DeclarationWithoutName, + + BracketOnNonArrayOrPointer, + BracketIndexNotInteger, + + ArrowOnNonPointer, + + SizeofIncompleteType, + + NegativeArraySize, + ArraySizeNotInteger, + + MemberAccessOnNonStructOrUnion, + + MultipleVariableDefinition(String), + VariableNotFound(String), + + NestedFunctionDefinition, + + FunctionDifferentSignature(String), + MultipleFunctionDefinition(String), } diff --git a/src/ast2/expression.rs b/src/ast2/expression.rs index a631245..7c29110 100644 --- a/src/ast2/expression.rs +++ b/src/ast2/expression.rs @@ -1,28 +1,34 @@ use crate::ast; -use super::PrimitiveType; +use super::{CVType, VariableInfo}; #[derive(Debug, Clone)] pub enum Expression { - SizeofExpr(Box), + I8(i8), + I16(i16), + I32(i32), + I64(i64), + U8(u8), + U16(u16), + U32(u32), + U64(u64), + F32(f32), + F64(f64), + String(String), + + Variable(VariableInfo), Conditional(ExprConditional), + Cast(ExprCast), + Paren(ExprParen), + Bracket(ExprBracket), + Arrow(ExprArrow), Unary(ExprUnary), Binary(ExprBinary), InitializerList(ExprInitializerList), } -impl Expression { - pub fn get_primitive_type(&self) -> Option { - match self { - Expression::SizeofExpr(_) => Some(PrimitiveType::UnsignedLong), - Expression::Conditional(_) => None, - Expression::Unary(_) => None, - Expression::Binary(_) => None, - Expression::InitializerList(_) => None, - } - } -} +impl Expression {} #[derive(Debug, Clone)] pub struct ExprConditional { @@ -31,6 +37,29 @@ pub struct ExprConditional { pub else_expr: Box, } +#[derive(Debug, Clone)] +pub struct ExprCast { + pub expr: Box, + pub type_: CVType, +} + +#[derive(Debug, Clone)] +pub struct ExprParen { + pub src: Box, + pub args: Vec, +} + +#[derive(Debug, Clone)] +pub struct ExprBracket { + pub src: Box, + pub index: Box, +} +#[derive(Debug, Clone)] +pub struct ExprArrow { + pub src: Box, + pub member: String, +} + pub type ExprUnaryOp = ast::ExprUnaryOperator; #[derive(Debug, Clone)] diff --git a/src/ast2/mod.rs b/src/ast2/mod.rs index 21b0588..7e7d318 100644 --- a/src/ast2/mod.rs +++ b/src/ast2/mod.rs @@ -12,22 +12,38 @@ pub use statement::Statement; pub use statement::StmtCompound; pub use statement::StmtExpression; pub use statement::StmtFor; -pub use statement::StmtFunctionDefinition; pub use statement::StmtGoto; pub use statement::StmtIf; pub use statement::StmtLabeled; pub use statement::StmtReturn; pub use statement::StmtSwitch; pub use statement::StmtSwitchCase; +pub use statement::StmtVariableDeclaration; +pub use expression::ExprArrow; +pub use expression::ExprBinary; +pub use expression::ExprBinaryOp; +pub use expression::ExprBracket; +pub use expression::ExprCast; +pub use expression::ExprConditional; +pub use expression::ExprInitializerList; +pub use expression::ExprParen; +pub use expression::ExprUnary; +pub use expression::ExprUnaryOp; pub use expression::Expression; pub use label::LabelInfo; +pub use variable::Address; +pub use variable::VariableInfo; +pub use variable::VariablePool; + +pub use error::CompileError; + pub use declarator::CombinedDeclarator; -pub use error::ConversionError; + pub use typename::ArrayType; pub use typename::CVType; pub use typename::FunctionType; pub use typename::PrimitiveType; -pub use variable::VariableInfo; +pub use typename::StorageQualifier; diff --git a/src/ast2/scope.rs b/src/ast2/scope.rs index 31bc397..378065d 100644 --- a/src/ast2/scope.rs +++ b/src/ast2/scope.rs @@ -1,6 +1,7 @@ use std::{cell::RefCell, collections::HashMap, rc::Rc}; -use super::{FunctionType, LabelInfo}; +use super::VariablePool; +use super::{FunctionType, LabelInfo, VariableInfo}; #[derive(Debug, Clone)] pub enum Scope { @@ -32,32 +33,44 @@ pub struct BlockScope { #[derive(Debug, Clone)] pub struct VariableScope { pub name: String, + pub info: VariableInfo, } #[derive(Clone)] pub struct FunctionScope { pub name: String, pub type_: FunctionType, - pub stack_size: usize, pub labels: HashMap>>, + pub pool: VariablePool, } impl FunctionScope { pub fn new(name: String, type_: FunctionType) -> Self { FunctionScope { name, type_, - stack_size: 0, labels: HashMap::new(), + pool: VariablePool::new(), } } } #[derive(Debug, Clone)] -pub struct GlobalScope { +pub struct FunctionDefinition { + pub body: Box, pub stack_size: usize, } +#[derive(Debug, Clone)] +pub struct GlobalScope { + pub variables: HashMap, + pub pool: VariablePool, + pub functions: Vec>>>, +} impl GlobalScope { pub fn new() -> Self { - GlobalScope { stack_size: 0 } + GlobalScope { + variables: HashMap::new(), + pool: VariablePool::new(), + functions: Vec::new(), + } } } diff --git a/src/ast2/statement.rs b/src/ast2/statement.rs index 0fc21d4..ce8a29e 100644 --- a/src/ast2/statement.rs +++ b/src/ast2/statement.rs @@ -1,6 +1,6 @@ use std::{cell::RefCell, rc::Rc}; -use super::{Expression, FunctionType, LabelInfo}; +use super::{Expression, LabelInfo, VariableInfo}; #[derive(Debug, Clone)] pub enum Statement { @@ -21,7 +21,8 @@ pub enum Statement { For(StmtFor), While(StmtWhile), DoWhile(StmtDoWhile), - FunctionDefinition(StmtFunctionDefinition), + + VariableDeclaration(StmtVariableDeclaration), } #[derive(Debug, Clone)] @@ -98,9 +99,7 @@ pub struct StmtDoWhile { } #[derive(Debug, Clone)] -pub struct StmtFunctionDefinition { - pub name: String, - pub definition: FunctionType, - pub body: Box, - pub stack_size: usize, +pub struct StmtVariableDeclaration { + /// (variable, initial value) pairs + pub pairs: Vec<(VariableInfo, Expression)>, } diff --git a/src/ast2/typename.rs b/src/ast2/typename.rs index 0fc4f89..41ab18b 100644 --- a/src/ast2/typename.rs +++ b/src/ast2/typename.rs @@ -20,12 +20,78 @@ pub enum PrimitiveType { Array(ArrayType), Function(FunctionType), } +impl PrimitiveType { + pub fn is_integer(&self) -> bool { + match self { + PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 => true, + _ => false, + } + } + pub fn is_numeric(&self) -> bool { + match self { + PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 => true, + _ => false, + } + } + pub fn is_float(&self) -> bool { + match self { + PrimitiveType::Float32 | PrimitiveType::Float64 => true, + _ => false, + } + } +} + +impl PartialEq for PrimitiveType { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (PrimitiveType::Void, PrimitiveType::Void) => true, + (PrimitiveType::UInt8, PrimitiveType::UInt8) => true, + (PrimitiveType::UInt16, PrimitiveType::UInt16) => true, + (PrimitiveType::UInt32, PrimitiveType::UInt32) => true, + (PrimitiveType::UInt64, PrimitiveType::UInt64) => true, + (PrimitiveType::Int8, PrimitiveType::Int8) => true, + (PrimitiveType::Int16, PrimitiveType::Int16) => true, + (PrimitiveType::Int32, PrimitiveType::Int32) => true, + (PrimitiveType::Int64, PrimitiveType::Int64) => true, + (PrimitiveType::Float32, PrimitiveType::Float32) => true, + (PrimitiveType::Float64, PrimitiveType::Float64) => true, + (PrimitiveType::Struct, PrimitiveType::Struct) => true, + (PrimitiveType::Union, PrimitiveType::Union) => true, + (PrimitiveType::Enum, PrimitiveType::Enum) => true, + (PrimitiveType::Pointer(a), PrimitiveType::Pointer(b)) => a == b, + (PrimitiveType::Array(a), PrimitiveType::Array(b)) => a == b, + (PrimitiveType::Function(a), PrimitiveType::Function(b)) => a == b, + _ => false, + } + } +} #[derive(Debug, Clone)] pub struct ArrayType { pub type_: Box, pub size: usize, } +impl PartialEq for ArrayType { + fn eq(&self, other: &Self) -> bool { + self.type_ == other.type_ && self.size == other.size + } +} #[derive(Debug, Clone)] pub struct FunctionType { // maybe no need CV qualifier for return type? @@ -33,6 +99,13 @@ pub struct FunctionType { pub args: Vec, pub variadic: bool, } +impl PartialEq for FunctionType { + fn eq(&self, other: &Self) -> bool { + self.return_type == other.return_type + && self.args == other.args + && self.variadic == other.variadic + } +} #[derive(Debug, Clone)] pub struct CVType { @@ -67,3 +140,28 @@ impl CVType { } } } +impl PartialEq for CVType { + fn eq(&self, other: &Self) -> bool { + self.type_ == other.type_ && self.const_ == other.const_ && self.volatile == other.volatile + } +} + +#[derive(Debug, Clone)] +pub struct StorageQualifier { + pub static_: bool, + pub register: bool, + pub extern_: bool, + pub typedef: bool, + pub auto: bool, +} +impl StorageQualifier { + pub fn new() -> Self { + Self { + static_: false, + register: false, + extern_: false, + typedef: false, + auto: false, + } + } +} diff --git a/src/ast2/variable.rs b/src/ast2/variable.rs index 7b5d5f3..56a25cc 100644 --- a/src/ast2/variable.rs +++ b/src/ast2/variable.rs @@ -1,3 +1,44 @@ +use super::CVType; + +#[derive(Debug, Clone)] pub struct VariableInfo { pub name: String, + pub address: Address, + pub cv_type: CVType, +} + +#[derive(Debug, Clone)] +pub struct VariablePool { + pub max_size: usize, + pub size: usize, +} + +impl VariablePool { + pub fn new() -> Self { + VariablePool { + max_size: 0, + size: 0, + } + } + + pub fn add(&mut self, size: usize, align: usize) -> usize { + let offset = (self.size + align - 1) / align * align; + self.size = offset + size; + self.max_size = self.max_size.max(self.size); + offset + } + #[allow(unused)] + pub fn remove(&mut self, size: usize, align: usize) { + self.size -= size; + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum Address { + /// absolute index + Global(usize), + /// relative index from base pointer + Local(usize), + /// index on function array + Function(usize), } From a722eb274008688045dc6606eff4bced7ff227e8 Mon Sep 17 00:00:00 2001 From: ehwan Date: Wed, 30 Oct 2024 15:22:25 +0900 Subject: [PATCH 05/10] add struct, union, enum type declaration and definition --- src/ast2/context.rs | 658 ++++++++++++++++++++++++++++++++++++++--- src/ast2/declarator.rs | 58 ++++ src/ast2/error.rs | 14 +- src/ast2/expression.rs | 15 +- src/ast2/mod.rs | 6 +- src/ast2/scope.rs | 8 +- src/ast2/typename.rs | 144 +++++---- src/ast2/variable.rs | 12 +- 8 files changed, 779 insertions(+), 136 deletions(-) diff --git a/src/ast2/context.rs b/src/ast2/context.rs index 268c59b..9754ae3 100644 --- a/src/ast2/context.rs +++ b/src/ast2/context.rs @@ -1,6 +1,7 @@ use std::cell::RefCell; use std::rc::Rc; +use super::declarator; use super::expression; use super::statement; use super::Address; @@ -8,15 +9,17 @@ use super::ArrayType; use super::CVType; use super::CombinedDeclarator; use super::CompileError; +use super::EnumType; use super::Expression; use super::FunctionType; use super::PrimitiveType; use super::Statement; use super::StmtSwitchCase; +use super::StmtVariableDeclaration; use super::StorageQualifier; +use super::StructType; use super::VariableInfo; use crate::ast; -use crate::ast2::StmtVariableDeclaration; use super::scope::BlockScope; use super::scope::FunctionDefinition; @@ -70,8 +73,16 @@ impl Context { None } fn end_switch_scope(&mut self) -> Result { - // @TODO pop every variable scope until switch scope - unimplemented!("end_switch_scope") + loop { + let scope = self.scopes.pop().unwrap(); + match scope { + Scope::Switch(scope) => return Ok(scope), + Scope::Variable(scope) => { + self.end_varaible_scope(scope)?; + } + _ => unreachable!("end_switch_scope: unexpected scope"), + } + } } fn begin_loop_scope(&mut self) -> Result<(), CompileError> { let scope = LoopScope { @@ -81,20 +92,46 @@ impl Context { Ok(()) } fn end_loop_scope(&mut self) -> Result { - // @TODO pop every variable scope until loop scope - unimplemented!("end_loop_scope") + loop { + let scope = self.scopes.pop().unwrap(); + match scope { + Scope::Loop(scope) => return Ok(scope), + Scope::Variable(scope) => { + self.end_varaible_scope(scope)?; + } + _ => unreachable!("end_switch_scope: unexpected scope"), + } + } } fn begin_scope(&mut self) -> Result<(), CompileError> { let scope = BlockScope { id: self.generate_scope_id(), + typedefs: Default::default(), }; self.scopes.push(Scope::Block(scope)); Ok(()) } + fn nearest_scope(&mut self) -> Option<&mut BlockScope> { + for scope in self.scopes.iter_mut().rev() { + match scope { + Scope::Block(scope) => return Some(scope), + _ => {} + } + } + None + } fn end_scope(&mut self) -> Result { - // @TODO pop every variable scope until block scope - unimplemented!("end_scope") + loop { + let scope = self.scopes.pop().unwrap(); + match scope { + Scope::Block(scope) => return Ok(scope), + Scope::Variable(scope) => { + self.end_varaible_scope(scope)?; + } + _ => unreachable!("end_switch_scope: unexpected scope"), + } + } } fn begin_function_scope( @@ -102,11 +139,23 @@ impl Context { name: String, type_: FunctionType, ) -> Result<(), CompileError> { - unimplemented!("begin_function_scope") + if self.function_scope.is_some() { + return Err(CompileError::NestedFunctionDefinition); + } + let scope = FunctionScope::new(name, type_); + self.function_scope = Some(scope); + Ok(()) } fn end_function_scope(&mut self) -> Result { - // @TODO pop every variable scope until function scope - unimplemented!("end_function_scope") + while let Some(scope) = self.scopes.pop() { + match scope { + Scope::Variable(scope) => { + self.end_varaible_scope(scope)?; + } + _ => unreachable!("end_switch_scope: unexpected scope"), + } + } + Ok(std::mem::take(&mut self.function_scope).unwrap()) } fn begin_variable_scope( @@ -128,7 +177,7 @@ impl Context { let size = self.type_sizeof(&type_.type_)?; let align = self.type_alignof(&type_.type_)?; - let offset = self.function_scope.as_mut().unwrap().pool.add(size, align); + let offset = self.function_scope.as_mut().unwrap().pool.push(size, align); let varinfo = VariableInfo { name: name.clone(), address: Address::Local(offset), @@ -141,6 +190,15 @@ impl Context { self.scopes.push(Scope::Variable(scope)); Ok(varinfo) } + fn end_varaible_scope(&mut self, scope: VariableScope) -> Result<(), CompileError> { + if let Some(func) = &mut self.function_scope { + func.pool.pop(); + } else { + self.global_scope.pool.pop(); + self.global_scope.variables.remove(&scope.name); + } + Ok(()) + } fn can_continue(&self) -> bool { for scope in self.scopes.iter().rev() { @@ -565,7 +623,7 @@ impl Context { let size = self.type_sizeof(&init_type.cv_type.type_)?; let align = self.type_alignof(&init_type.cv_type.type_)?; - let offset = self.global_scope.pool.add(size, align); + let offset = self.global_scope.pool.push(size, align); let varinfo = VariableInfo { name: name.clone(), address: Address::Global(offset), @@ -590,7 +648,395 @@ impl Context { None => { // struct, union, enum type definition // or just ill-formed declaration (but it's not an error) - unreachable!("process_statement_declaration: struct, union, enum definition") + + match base_type.type_ { + PrimitiveType::Struct(struct_definition) => { + match struct_definition.body { + Some(struct_body) => { + let Some(name) = struct_definition.name else { + // anonymous struct definition, ill-formed. + // skip this statement + return Ok(Statement::None); + }; + if let Some(current_scope) = self.nearest_scope() { + // check if there is other variable with same name + if let Some(old) = current_scope.typedefs.get_mut(&name) { + // type name `name` exists. + // check if it's struct declaration of same type + + let PrimitiveType::Struct(other_struct_def) = + &mut old.type_ + else { + // it is not struct, + // redifinition of type name `name` + return Err(CompileError::TypeRedifinition(name)); + }; + + // if old struct has definition, it's redifinition + if other_struct_def.body.is_some() { + return Err(CompileError::TypeRedifinition(name)); + } + other_struct_def.body = Some(struct_body); + } else { + let struct_type = StructType { + name: Some(name.clone()), + body: Some(struct_body), + }; + let struct_type = PrimitiveType::Struct(struct_type); + current_scope + .typedefs + .insert(name, CVType::from_primitive(struct_type)); + } + } else { + // global scope + + // check if there is other variable with same name + if let Some(old) = self.global_scope.typedefs.get_mut(&name) { + // type name `name` exists. + // check if it's struct declaration of same type + + let PrimitiveType::Struct(other_struct_def) = + &mut old.type_ + else { + // it is not struct, + // redifinition of type name `name` + return Err(CompileError::TypeRedifinition(name)); + }; + + // if old struct has definition, it's redifinition + if other_struct_def.body.is_some() { + return Err(CompileError::TypeRedifinition(name)); + } + other_struct_def.body = Some(struct_body); + } else { + let struct_type = StructType { + name: Some(name.clone()), + body: Some(struct_body), + }; + let struct_type = PrimitiveType::Struct(struct_type); + self.global_scope + .typedefs + .insert(name, CVType::from_primitive(struct_type)); + } + } + } + None => { + // declaration + let Some(name) = struct_definition.name else { + // anonymous struct definition, ill-formed. + // skip this statement + return Ok(Statement::None); + }; + if let Some(current_scope) = self.nearest_scope() { + // check if there is other variable with same name + if let Some(old) = current_scope.typedefs.get(&name) { + // type name `name` exists. + // check if it's struct declaration of same type + + let PrimitiveType::Struct(other_struct_def) = &old.type_ + else { + // it is not struct, + // redifinition of type name `name` + return Err(CompileError::TypeRedifinition(name)); + }; + } else { + let struct_type = StructType { + name: Some(name.clone()), + body: None, + }; + let struct_type = PrimitiveType::Struct(struct_type); + current_scope + .typedefs + .insert(name, CVType::from_primitive(struct_type)); + } + } else { + // global scope + // check if there is other variable with same name + if let Some(old) = self.global_scope.typedefs.get(&name) { + // type name `name` exists. + // check if it's struct declaration of same type + + let PrimitiveType::Struct(other_struct_def) = &old.type_ + else { + // it is not struct, + // redifinition of type name `name` + return Err(CompileError::TypeRedifinition(name)); + }; + } else { + let struct_type = StructType { + name: Some(name.clone()), + body: None, + }; + let struct_type = PrimitiveType::Struct(struct_type); + self.global_scope + .typedefs + .insert(name, CVType::from_primitive(struct_type)); + } + } + } + } + Ok(Statement::None) + } + PrimitiveType::Union(union_definition) => { + match union_definition.body { + Some(union_body) => { + let Some(name) = union_definition.name else { + // anonymous union definition, ill-formed. + // skip this statement + return Ok(Statement::None); + }; + if let Some(current_scope) = self.nearest_scope() { + // check if there is other variable with same name + if let Some(old) = current_scope.typedefs.get_mut(&name) { + // type name `name` exists. + // check if it's union declaration of same type + + let PrimitiveType::Union(other_union_def) = &mut old.type_ + else { + // it is not union, + // redifinition of type name `name` + return Err(CompileError::TypeRedifinition(name)); + }; + + // if old union has definition, it's redifinition + if other_union_def.body.is_some() { + return Err(CompileError::TypeRedifinition(name)); + } + other_union_def.body = Some(union_body); + } else { + let union_type = StructType { + name: Some(name.clone()), + body: Some(union_body), + }; + let union_type = PrimitiveType::Union(union_type); + current_scope + .typedefs + .insert(name, CVType::from_primitive(union_type)); + } + } else { + // global scope + + // check if there is other variable with same name + if let Some(old) = self.global_scope.typedefs.get_mut(&name) { + // type name `name` exists. + // check if it's union declaration of same type + + let PrimitiveType::Union(other_union_def) = &mut old.type_ + else { + // it is not union, + // redifinition of type name `name` + return Err(CompileError::TypeRedifinition(name)); + }; + + // if old union has definition, it's redifinition + if other_union_def.body.is_some() { + return Err(CompileError::TypeRedifinition(name)); + } + other_union_def.body = Some(union_body); + } else { + let union_type = StructType { + name: Some(name.clone()), + body: Some(union_body), + }; + let union_type = PrimitiveType::Union(union_type); + self.global_scope + .typedefs + .insert(name, CVType::from_primitive(union_type)); + } + } + } + None => { + // declaration + let Some(name) = union_definition.name else { + // anonymous union definition, ill-formed. + // skip this statement + return Ok(Statement::None); + }; + if let Some(current_scope) = self.nearest_scope() { + // check if there is other variable with same name + if let Some(old) = current_scope.typedefs.get(&name) { + // type name `name` exists. + // check if it's union declaration of same type + + let PrimitiveType::Union(other_union_def) = &old.type_ + else { + // it is not union, + // redifinition of type name `name` + return Err(CompileError::TypeRedifinition(name)); + }; + } else { + let union_type = StructType { + name: Some(name.clone()), + body: None, + }; + let union_type = PrimitiveType::Union(union_type); + current_scope + .typedefs + .insert(name, CVType::from_primitive(union_type)); + } + } else { + // global scope + // check if there is other variable with same name + if let Some(old) = self.global_scope.typedefs.get(&name) { + // type name `name` exists. + // check if it's union declaration of same type + + let PrimitiveType::Union(other_union_def) = &old.type_ + else { + // it is not union, + // redifinition of type name `name` + return Err(CompileError::TypeRedifinition(name)); + }; + } else { + let union_type = StructType { + name: Some(name.clone()), + body: None, + }; + let union_type = PrimitiveType::Union(union_type); + self.global_scope + .typedefs + .insert(name, CVType::from_primitive(union_type)); + } + } + } + } + Ok(Statement::None) + } + PrimitiveType::Enum(enum_definition) => { + match enum_definition.body { + Some(enum_body) => { + let Some(name) = enum_definition.name else { + // anonymous enum definition, ill-formed. + // skip this statement + return Ok(Statement::None); + }; + if let Some(current_scope) = self.nearest_scope() { + // check if there is other variable with same name + if let Some(old) = current_scope.typedefs.get_mut(&name) { + // type name `name` exists. + // check if it's enum declaration of same type + + let PrimitiveType::Enum(other_enum_def) = &mut old.type_ + else { + // it is not enum, + // redifinition of type name `name` + return Err(CompileError::TypeRedifinition(name)); + }; + + // if old enum has definition, it's redifinition + if other_enum_def.body.is_some() { + return Err(CompileError::TypeRedifinition(name)); + } + other_enum_def.body = Some(enum_body); + } else { + let enum_type = EnumType { + name: Some(name.clone()), + body: Some(enum_body), + type_: enum_definition.type_, + }; + let enum_type = PrimitiveType::Enum(enum_type); + current_scope + .typedefs + .insert(name, CVType::from_primitive(enum_type)); + } + } else { + // global scope + + // check if there is other variable with same name + if let Some(old) = self.global_scope.typedefs.get_mut(&name) { + // type name `name` exists. + // check if it's enum declaration of same type + + let PrimitiveType::Enum(other_enum_def) = &mut old.type_ + else { + // it is not enum, + // redifinition of type name `name` + return Err(CompileError::TypeRedifinition(name)); + }; + + // if old enum has definition, it's redifinition + if other_enum_def.body.is_some() { + return Err(CompileError::TypeRedifinition(name)); + } + other_enum_def.body = Some(enum_body); + } else { + let enum_type = EnumType { + name: Some(name.clone()), + body: Some(enum_body), + type_: enum_definition.type_, + }; + let enum_type = PrimitiveType::Enum(enum_type); + self.global_scope + .typedefs + .insert(name, CVType::from_primitive(enum_type)); + } + } + } + None => { + // declaration + let Some(name) = enum_definition.name else { + // anonymous enum definition, ill-formed. + // skip this statement + return Ok(Statement::None); + }; + if let Some(current_scope) = self.nearest_scope() { + // check if there is other variable with same name + if let Some(old) = current_scope.typedefs.get(&name) { + // type name `name` exists. + // check if it's enum declaration of same type + + let PrimitiveType::Enum(other_enum_def) = &old.type_ else { + // it is not enum, + // redifinition of type name `name` + return Err(CompileError::TypeRedifinition(name)); + }; + } else { + let enum_type = EnumType { + name: Some(name.clone()), + body: None, + type_: enum_definition.type_, + }; + let enum_type = PrimitiveType::Enum(enum_type); + current_scope + .typedefs + .insert(name, CVType::from_primitive(enum_type)); + } + } else { + // global scope + // check if there is other variable with same name + if let Some(old) = self.global_scope.typedefs.get(&name) { + // type name `name` exists. + // check if it's enum declaration of same type + + let PrimitiveType::Enum(other_enum_def) = &old.type_ else { + // it is not enum, + // redifinition of type name `name` + return Err(CompileError::TypeRedifinition(name)); + }; + } else { + let enum_type = EnumType { + name: Some(name.clone()), + body: None, + type_: enum_definition.type_, + }; + let enum_type = PrimitiveType::Enum(enum_type); + self.global_scope + .typedefs + .insert(name, CVType::from_primitive(enum_type)); + } + } + } + } + Ok(Statement::None) + } + + _ => { + // ill-formed declaration + // int; <-- + // but it's not an error + Ok(Statement::None) + } + } } } } @@ -619,7 +1065,9 @@ impl Context { let (function_definition, function_type) = match decl.cv_type.type_ { PrimitiveType::Function(func) => { self.begin_function_scope(name.clone(), func.clone())?; + self.begin_scope()?; let body = self.process_statement(*stmt.body)?; + self.end_scope()?; let scope = self.end_function_scope()?; ( FunctionDefinition { @@ -701,6 +1149,8 @@ impl Context { Expression::Paren(expr) => unimplemented!("expression_type Paren"), Expression::Binary(expr) => unimplemented!("expression_type Binary"), Expression::Unary(expr) => unimplemented!("expression_type Unary"), + Expression::Member(expr) => expr.member_type.clone(), + Expression::Arrow(expr) => expr.member_type.clone(), } } pub(crate) fn process_expression_identifier( @@ -778,25 +1228,56 @@ impl Context { ) -> Result { let src = self.process_expression(*expr.src)?; match self.expression_type(&src).type_ { - PrimitiveType::Struct | PrimitiveType::Union => {} - _ => return Err(CompileError::MemberAccessOnNonStructOrUnion), + PrimitiveType::Struct(s) | PrimitiveType::Union(s) => { + let Some(body) = &s.body else { + return Err(CompileError::MemberOnIncompleteType); + }; + + for member in body.members.iter() { + if expr.member == member.name { + return Ok(Expression::Member(expression::ExprMember { + src: Box::new(src), + member_offset: member.offset, + member_type: member.cv_type.clone(), + })); + } + } + + return Err(CompileError::MemberNotFound(expr.member)); + } + + _ => return Err(CompileError::MemberOnNonStructOrUnion), } - unreachable!("process_expression_member") } pub(crate) fn process_expression_arrow( &mut self, expr: ast::ExprArrow, ) -> Result { let src = self.process_expression(*expr.src)?; - match self.expression_type(&src).type_ { - PrimitiveType::Pointer(_) => {} - _ => return Err(CompileError::ArrowOnNonPointer), - } + let PrimitiveType::Pointer(src_type) = self.expression_type(&src).type_ else { + return Err(CompileError::ArrowOnNonPointer); + }; + match src_type.type_ { + PrimitiveType::Struct(s) | PrimitiveType::Union(s) => { + let Some(body) = &s.body else { + return Err(CompileError::ArrowOnIncompleteType); + }; - Ok(Expression::Arrow(expression::ExprArrow { - src: Box::new(src), - member: expr.member, - })) + for member in body.members.iter() { + if expr.member == member.name { + return Ok(Expression::Arrow(expression::ExprMember { + src: Box::new(src), + member_offset: member.offset, + member_type: member.cv_type.clone(), + })); + } + } + + return Err(CompileError::ArrowNotFound(expr.member)); + } + + _ => return Err(CompileError::ArrowOnNonStructOrUnion), + } } pub(crate) fn process_expression_bracket( &mut self, @@ -929,13 +1410,16 @@ impl Context { PrimitiveType::UInt32 | PrimitiveType::Int32 | PrimitiveType::Float32 => 4, PrimitiveType::UInt64 | PrimitiveType::Int64 | PrimitiveType::Float64 => 8, PrimitiveType::Pointer(_) => 8, - PrimitiveType::Array(ArrayType { type_, size }) => { - self.type_sizeof(&type_.type_)? * (*size) - } + PrimitiveType::Array(ArrayType { + cv_type: type_, + size, + }) => self.type_sizeof(&type_.type_)? * (*size), PrimitiveType::Function(_) => return Err(CompileError::SizeofIncompleteType), - PrimitiveType::Struct | PrimitiveType::Union | PrimitiveType::Enum => { - unreachable!("size_of for struct/union/enum") - } + PrimitiveType::Struct(s) | PrimitiveType::Union(s) => match &s.body { + Some(s) => s.size, + None => return Err(CompileError::SizeofIncompleteType), + }, + PrimitiveType::Enum(e) => self.type_sizeof(&e.type_)?, }) } pub fn type_alignof(&self, typename: &PrimitiveType) -> Result { @@ -946,13 +1430,16 @@ impl Context { PrimitiveType::UInt32 | PrimitiveType::Int32 | PrimitiveType::Float32 => 4, PrimitiveType::UInt64 | PrimitiveType::Int64 | PrimitiveType::Float64 => 8, PrimitiveType::Pointer(_) => 8, - PrimitiveType::Array(ArrayType { type_, size: _ }) => { - self.type_alignof(&type_.type_)? - } + PrimitiveType::Array(ArrayType { + cv_type: type_, + size: _, + }) => self.type_alignof(&type_.type_)?, PrimitiveType::Function(_) => return Err(CompileError::SizeofIncompleteType), - PrimitiveType::Struct | PrimitiveType::Union | PrimitiveType::Enum => { - unreachable!("size_of for struct/union/enum") - } + PrimitiveType::Struct(s) | PrimitiveType::Union(s) => match &s.body { + Some(s) => s.align, + None => return Err(CompileError::AlignofIncompleteType), + }, + PrimitiveType::Enum(e) => self.type_alignof(&e.type_)?, }) } @@ -960,13 +1447,72 @@ impl Context { &mut self, mut specs: impl Iterator, ) -> Result { - unimplemented!("process_specs") + let mut collector = declarator::SpecifierQualifierCollector::new(); + for s in specs { + match s { + ast::SpecifierQualifier::TypeQualifier(t) => match t { + ast::TypeQualifier::Const => collector.set_const()?, + ast::TypeQualifier::Volatile => collector.set_volatile()?, + }, + ast::SpecifierQualifier::TypeSpecifier(s) => match s { + ast::TypeSpecifier::Void => collector.set_void()?, + ast::TypeSpecifier::Char => collector.set_char()?, + ast::TypeSpecifier::Short => collector.set_short()?, + ast::TypeSpecifier::Int => collector.set_int()?, + ast::TypeSpecifier::Long => collector.set_long()?, + ast::TypeSpecifier::Float => collector.set_float()?, + ast::TypeSpecifier::Double => collector.set_double()?, + ast::TypeSpecifier::Signed => collector.set_signed()?, + ast::TypeSpecifier::Unsigned => collector.set_unsigned()?, + ast::TypeSpecifier::Typename(name) => unimplemented!("process_specs-typename"), + ast::TypeSpecifier::StructOrUnion(s) => unimplemented!("process_specs-struct"), + ast::TypeSpecifier::Enum(e) => unimplemented!("process_specs-enum"), + }, + } + } + collector.into_type() } pub(crate) fn process_decl_specs( &mut self, mut specs: impl Iterator, ) -> Result<(StorageQualifier, CVType), CompileError> { - unimplemented!("process_specs") + let mut storage_qualifier = StorageQualifier::new(); + let mut collector = declarator::SpecifierQualifierCollector::new(); + + for s in specs { + match s { + ast::DeclarationSpecifier::StorageClassSpecifier(s) => match s { + ast::StorageClassSpecifier::Auto => storage_qualifier.auto = true, + ast::StorageClassSpecifier::Register => storage_qualifier.register = true, + ast::StorageClassSpecifier::Static => storage_qualifier.static_ = true, + ast::StorageClassSpecifier::Extern => storage_qualifier.extern_ = true, + ast::StorageClassSpecifier::Typedef => storage_qualifier.typedef = true, + }, + ast::DeclarationSpecifier::TypeQualifier(t) => match t { + ast::TypeQualifier::Const => collector.set_const()?, + ast::TypeQualifier::Volatile => collector.set_volatile()?, + }, + ast::DeclarationSpecifier::TypeSpecifier(s) => match s { + ast::TypeSpecifier::Void => collector.set_void()?, + ast::TypeSpecifier::Char => collector.set_char()?, + ast::TypeSpecifier::Short => collector.set_short()?, + ast::TypeSpecifier::Int => collector.set_int()?, + ast::TypeSpecifier::Long => collector.set_long()?, + ast::TypeSpecifier::Float => collector.set_float()?, + ast::TypeSpecifier::Double => collector.set_double()?, + ast::TypeSpecifier::Signed => collector.set_signed()?, + ast::TypeSpecifier::Unsigned => collector.set_unsigned()?, + ast::TypeSpecifier::Typename(name) => { + unimplemented!("process_decl_specs-typename") + } + ast::TypeSpecifier::StructOrUnion(s) => { + unimplemented!("process_decl_specs-struct") + } + ast::TypeSpecifier::Enum(e) => unimplemented!("process_decl_specs-enum"), + }, + } + } + Ok((storage_qualifier, collector.into_type()?)) } pub(crate) fn process_declarator_identifier( &mut self, @@ -1038,7 +1584,7 @@ impl Context { if let Some(decl) = decl.declarator { let mut res = self.process_declarator(*decl, base_type)?; res.cv_type = CVType::from_primitive(PrimitiveType::Array(ArrayType { - type_: Box::new(res.cv_type), + cv_type: Box::new(res.cv_type), size: size, })); Ok(res) @@ -1046,7 +1592,7 @@ impl Context { Ok(CombinedDeclarator { name: None, cv_type: CVType::from_primitive(PrimitiveType::Array(ArrayType { - type_: Box::new(base_type), + cv_type: Box::new(base_type), size: size, })), }) @@ -1057,16 +1603,40 @@ impl Context { decl: ast::DeclArrayUnbounded, base_type: CVType, ) -> Result { + unimplemented!("process_declarator_array_unbounded") } pub(crate) fn process_declarator_function( &mut self, decl: ast::DeclFunction, base_type: CVType, ) -> Result { - if let Some(decl) = decl.declarator { - let res = self.process_declarator(*decl, base_type)?; - } else { - } + let args = decl + .params + .params + .into_iter() + .map(|param| -> Result { + // @TODO storage_qualifier check + let (_storage_qualifier, base_type) = + self.process_decl_specs(param.specs.into_iter())?; + + if let Some(decl) = param.declarator { + let res = self.process_declarator(*decl, base_type)?; + Ok(res.cv_type) + } else { + Ok(base_type) + } + }) + .collect::, _>>()?; + let variadic = decl.params.variadic; + + unimplemented!("process_declarator_function") + + // if let Some(decl) = decl.declarator { + // let res = self.process_declarator(*decl, base_type)?; + // FunctionType { args, variadic, + // } else { + // FunctionType { args, variadic, + // } } pub(crate) fn process_declarator_const( &mut self, diff --git a/src/ast2/declarator.rs b/src/ast2/declarator.rs index 88cdef7..bc9be95 100644 --- a/src/ast2/declarator.rs +++ b/src/ast2/declarator.rs @@ -1,4 +1,5 @@ use super::CVType; +use super::CompileError; #[derive(Debug, Clone)] pub struct CombinedDeclarator { @@ -6,3 +7,60 @@ pub struct CombinedDeclarator { pub name: Option, pub cv_type: CVType, } + +pub(crate) struct SpecifierQualifierCollector {} + +impl SpecifierQualifierCollector { + pub fn new() -> Self { + Self {} + } + pub fn set_const(&mut self) -> Result<(), CompileError> { + unimplemented!() + } + pub fn set_volatile(&mut self) -> Result<(), CompileError> { + unimplemented!() + } + pub fn set_int(&mut self) -> Result<(), CompileError> { + unimplemented!() + } + pub fn set_char(&mut self) -> Result<(), CompileError> { + unimplemented!() + } + pub fn set_short(&mut self) -> Result<(), CompileError> { + unimplemented!() + } + pub fn set_long(&mut self) -> Result<(), CompileError> { + unimplemented!() + } + pub fn set_signed(&mut self) -> Result<(), CompileError> { + unimplemented!() + } + pub fn set_unsigned(&mut self) -> Result<(), CompileError> { + unimplemented!() + } + pub fn set_float(&mut self) -> Result<(), CompileError> { + unimplemented!() + } + pub fn set_double(&mut self) -> Result<(), CompileError> { + unimplemented!() + } + pub fn set_void(&mut self) -> Result<(), CompileError> { + unimplemented!() + } + pub fn set_struct(&mut self) -> Result<(), CompileError> { + unimplemented!() + } + pub fn set_union(&mut self) -> Result<(), CompileError> { + unimplemented!() + } + pub fn set_enum(&mut self) -> Result<(), CompileError> { + unimplemented!() + } + pub fn set_typename(&mut self) -> Result<(), CompileError> { + unimplemented!() + } + + pub fn into_type(self) -> Result { + unimplemented!() + } +} diff --git a/src/ast2/error.rs b/src/ast2/error.rs index c449f9c..f8bb915 100644 --- a/src/ast2/error.rs +++ b/src/ast2/error.rs @@ -24,14 +24,20 @@ pub enum CompileError { BracketOnNonArrayOrPointer, BracketIndexNotInteger, - ArrowOnNonPointer, - SizeofIncompleteType, + AlignofIncompleteType, NegativeArraySize, ArraySizeNotInteger, - MemberAccessOnNonStructOrUnion, + MemberOnNonStructOrUnion, + MemberOnIncompleteType, + MemberNotFound(String), + + ArrowOnNonPointer, + ArrowOnNonStructOrUnion, + ArrowOnIncompleteType, + ArrowNotFound(String), MultipleVariableDefinition(String), VariableNotFound(String), @@ -40,4 +46,6 @@ pub enum CompileError { FunctionDifferentSignature(String), MultipleFunctionDefinition(String), + + TypeRedifinition(String), } diff --git a/src/ast2/expression.rs b/src/ast2/expression.rs index 7c29110..b15dec3 100644 --- a/src/ast2/expression.rs +++ b/src/ast2/expression.rs @@ -20,10 +20,11 @@ pub enum Expression { Conditional(ExprConditional), Cast(ExprCast), + Member(ExprMember), + Arrow(ExprMember), Paren(ExprParen), Bracket(ExprBracket), - Arrow(ExprArrow), Unary(ExprUnary), Binary(ExprBinary), InitializerList(ExprInitializerList), @@ -54,11 +55,6 @@ pub struct ExprBracket { pub src: Box, pub index: Box, } -#[derive(Debug, Clone)] -pub struct ExprArrow { - pub src: Box, - pub member: String, -} pub type ExprUnaryOp = ast::ExprUnaryOperator; @@ -81,3 +77,10 @@ pub struct ExprBinary { pub struct ExprInitializerList { pub exprs: Vec, } + +#[derive(Debug, Clone)] +pub struct ExprMember { + pub src: Box, + pub member_offset: usize, + pub member_type: CVType, +} diff --git a/src/ast2/mod.rs b/src/ast2/mod.rs index 7e7d318..dc24037 100644 --- a/src/ast2/mod.rs +++ b/src/ast2/mod.rs @@ -20,13 +20,13 @@ pub use statement::StmtSwitch; pub use statement::StmtSwitchCase; pub use statement::StmtVariableDeclaration; -pub use expression::ExprArrow; pub use expression::ExprBinary; pub use expression::ExprBinaryOp; pub use expression::ExprBracket; pub use expression::ExprCast; pub use expression::ExprConditional; pub use expression::ExprInitializerList; +pub use expression::ExprMember; pub use expression::ExprParen; pub use expression::ExprUnary; pub use expression::ExprUnaryOp; @@ -44,6 +44,10 @@ pub use declarator::CombinedDeclarator; pub use typename::ArrayType; pub use typename::CVType; +pub use typename::EnumMember; +pub use typename::EnumType; pub use typename::FunctionType; pub use typename::PrimitiveType; pub use typename::StorageQualifier; +pub use typename::StructMember; +pub use typename::StructType; diff --git a/src/ast2/scope.rs b/src/ast2/scope.rs index 378065d..dd0bb52 100644 --- a/src/ast2/scope.rs +++ b/src/ast2/scope.rs @@ -1,7 +1,7 @@ use std::{cell::RefCell, collections::HashMap, rc::Rc}; use super::VariablePool; -use super::{FunctionType, LabelInfo, VariableInfo}; +use super::{CVType, FunctionType, LabelInfo, VariableInfo}; #[derive(Debug, Clone)] pub enum Scope { @@ -28,6 +28,9 @@ pub struct LoopScope { #[derive(Debug, Clone)] pub struct BlockScope { pub id: usize, + + // `typedef`s and `struct`, `union`, `enum` definitions + pub typedefs: HashMap, } #[derive(Debug, Clone)] @@ -64,6 +67,8 @@ pub struct GlobalScope { pub variables: HashMap, pub pool: VariablePool, pub functions: Vec>>>, + // `typedef`s and `struct`, `union`, `enum` definitions + pub typedefs: HashMap, } impl GlobalScope { pub fn new() -> Self { @@ -71,6 +76,7 @@ impl GlobalScope { variables: HashMap::new(), pool: VariablePool::new(), functions: Vec::new(), + typedefs: HashMap::new(), } } } diff --git a/src/ast2/typename.rs b/src/ast2/typename.rs index 41ab18b..6d35a71 100644 --- a/src/ast2/typename.rs +++ b/src/ast2/typename.rs @@ -1,4 +1,4 @@ -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub enum PrimitiveType { Void, UInt8, @@ -12,9 +12,9 @@ pub enum PrimitiveType { Float32, Float64, - Struct, - Union, - Enum, + Struct(StructType), + Union(StructType), + Enum(EnumType), Pointer(Box), Array(ArrayType), @@ -22,92 +22,87 @@ pub enum PrimitiveType { } impl PrimitiveType { pub fn is_integer(&self) -> bool { - match self { + matches!( + self, PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 => true, - _ => false, - } + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + ) } pub fn is_numeric(&self) -> bool { - match self { + matches!( + self, PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 => true, - _ => false, - } + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 + ) } pub fn is_float(&self) -> bool { - match self { - PrimitiveType::Float32 | PrimitiveType::Float64 => true, - _ => false, - } - } -} - -impl PartialEq for PrimitiveType { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (PrimitiveType::Void, PrimitiveType::Void) => true, - (PrimitiveType::UInt8, PrimitiveType::UInt8) => true, - (PrimitiveType::UInt16, PrimitiveType::UInt16) => true, - (PrimitiveType::UInt32, PrimitiveType::UInt32) => true, - (PrimitiveType::UInt64, PrimitiveType::UInt64) => true, - (PrimitiveType::Int8, PrimitiveType::Int8) => true, - (PrimitiveType::Int16, PrimitiveType::Int16) => true, - (PrimitiveType::Int32, PrimitiveType::Int32) => true, - (PrimitiveType::Int64, PrimitiveType::Int64) => true, - (PrimitiveType::Float32, PrimitiveType::Float32) => true, - (PrimitiveType::Float64, PrimitiveType::Float64) => true, - (PrimitiveType::Struct, PrimitiveType::Struct) => true, - (PrimitiveType::Union, PrimitiveType::Union) => true, - (PrimitiveType::Enum, PrimitiveType::Enum) => true, - (PrimitiveType::Pointer(a), PrimitiveType::Pointer(b)) => a == b, - (PrimitiveType::Array(a), PrimitiveType::Array(b)) => a == b, - (PrimitiveType::Function(a), PrimitiveType::Function(b)) => a == b, - _ => false, - } + matches!(self, PrimitiveType::Float32 | PrimitiveType::Float64) } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct ArrayType { - pub type_: Box, + pub cv_type: Box, pub size: usize, } -impl PartialEq for ArrayType { - fn eq(&self, other: &Self) -> bool { - self.type_ == other.type_ && self.size == other.size - } -} -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct FunctionType { // maybe no need CV qualifier for return type? pub return_type: Box, pub args: Vec, pub variadic: bool, } -impl PartialEq for FunctionType { - fn eq(&self, other: &Self) -> bool { - self.return_type == other.return_type - && self.args == other.args - && self.variadic == other.variadic - } + +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct StructType { + pub name: Option, + pub body: Option, +} +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct StructBody { + pub members: Vec, + pub size: usize, + pub align: usize, +} +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct StructMember { + pub name: String, + pub cv_type: CVType, + pub offset: usize, +} + +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct EnumType { + pub name: Option, + pub body: Option, + /// integer representation of enum type + pub type_: Box, +} +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct EnumBody { + pub members: Vec, +} +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct EnumMember { + pub name: String, + pub value: i64, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct CVType { pub type_: PrimitiveType, pub const_: bool, @@ -132,7 +127,7 @@ impl CVType { pub fn into_array(self, size: usize) -> Self { Self { type_: PrimitiveType::Array(ArrayType { - type_: Box::new(self), + cv_type: Box::new(self), size, }), const_: false, @@ -140,13 +135,8 @@ impl CVType { } } } -impl PartialEq for CVType { - fn eq(&self, other: &Self) -> bool { - self.type_ == other.type_ && self.const_ == other.const_ && self.volatile == other.volatile - } -} -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct StorageQualifier { pub static_: bool, pub register: bool, diff --git a/src/ast2/variable.rs b/src/ast2/variable.rs index 56a25cc..e956a27 100644 --- a/src/ast2/variable.rs +++ b/src/ast2/variable.rs @@ -11,6 +11,8 @@ pub struct VariableInfo { pub struct VariablePool { pub max_size: usize, pub size: usize, + /// save `size` before `push()` to restore upon `pop()` + pub old_sizes: Vec, } impl VariablePool { @@ -18,18 +20,20 @@ impl VariablePool { VariablePool { max_size: 0, size: 0, + old_sizes: Vec::new(), } } - pub fn add(&mut self, size: usize, align: usize) -> usize { + pub fn push(&mut self, size: usize, align: usize) -> usize { + self.old_sizes.push(self.size); let offset = (self.size + align - 1) / align * align; self.size = offset + size; self.max_size = self.max_size.max(self.size); offset } - #[allow(unused)] - pub fn remove(&mut self, size: usize, align: usize) { - self.size -= size; + pub fn pop(&mut self) { + let size = self.old_sizes.pop().unwrap(); + self.size = size; } } From 135c4d54a18953f2138e73481b173cb03c3fcf30 Mon Sep 17 00:00:00 2001 From: Taehwan Kim Date: Wed, 30 Oct 2024 22:16:05 +0900 Subject: [PATCH 06/10] fixed lalr grammar was wrong for assignment - add virtual machine interface --- src/ast/mod.rs | 5 + src/ast/parser_lr.rs | 13 +- src/ast2/context.rs | 116 +++++++-- src/ast2/declarator.rs | 99 +++++++- src/ast2/error.rs | 9 + src/ast2/mod.rs | 3 + src/ast2/statement.rs | 5 + src/ast2/typename.rs | 30 +++ src/main.rs | 22 +- src/virtualmachine/function.rs | 1 - src/virtualmachine/generator.rs | 160 ++++++++++++ .../{instruction/mod.rs => instruction.rs} | 8 - src/virtualmachine/instruction/generation.rs | 238 ------------------ src/virtualmachine/mod.rs | 16 +- .../{instruction => }/operand.rs | 2 +- src/virtualmachine/program.rs | 78 ------ src/virtualmachine/scope.rs | 41 --- src/virtualmachine/vm.rs | 40 +++ 18 files changed, 471 insertions(+), 415 deletions(-) delete mode 100644 src/virtualmachine/function.rs create mode 100644 src/virtualmachine/generator.rs rename src/virtualmachine/{instruction/mod.rs => instruction.rs} (99%) delete mode 100644 src/virtualmachine/instruction/generation.rs rename src/virtualmachine/{instruction => }/operand.rs (96%) delete mode 100644 src/virtualmachine/program.rs delete mode 100644 src/virtualmachine/scope.rs create mode 100644 src/virtualmachine/vm.rs diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 8d58477..87f7841 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -3,6 +3,10 @@ mod expression; mod parser_lr; mod statement; +pub use parser_lr::translation_unitContext; +pub use parser_lr::translation_unitParseError; +pub use parser_lr::translation_unitParser; + pub use declarator::DeclArrayFixed; pub use declarator::DeclArrayUnbounded; pub use declarator::DeclConst; @@ -68,3 +72,4 @@ pub use statement::StmtNull; pub use statement::StmtReturn; pub use statement::StmtSwitch; pub use statement::StmtWhile; +pub use statement::TranslationUnit; diff --git a/src/ast/parser_lr.rs b/src/ast/parser_lr.rs index 48a6ff7..cf6aa0b 100644 --- a/src/ast/parser_lr.rs +++ b/src/ast/parser_lr.rs @@ -495,7 +495,7 @@ logical_or_expression( Expression ) conditional_expression( Expression ) : logical_or_expression - | logical_or_expression question expression colon conditional_expression { + | logical_or_expression question! expression colon! conditional_expression { Expression::Conditional( expression::ExprConditional{ cond: Box::new(logical_or_expression), then_expr: Box::new(expression), @@ -506,6 +506,13 @@ conditional_expression( Expression ) assignment_expression( Expression ) : conditional_expression + | unary_expression assign assignment_expression { + Expression::Binary( expression::ExprBinary{ + op: expression::ExprBinaryOperator::Assign, + lhs: Box::new(unary_expression), + rhs: Box::new(assignment_expression), + }) + } | unary_expression mul_assign assignment_expression { Expression::Binary( expression::ExprBinary{ op: expression::ExprBinaryOperator::MulAssign, @@ -1197,7 +1204,7 @@ enumerator( declarator::Enumerator ) value: None, } } - | ident eq constant_expression { + | ident assign constant_expression { let Token::Identifier(name) = ident else { unreachable!() }; declarator::Enumerator { name, @@ -1214,7 +1221,7 @@ init_declarator( declarator::DeclInit ) initializer: None, } } - | declarator eq initializer { + | declarator assign initializer { declarator::DeclInit{ declarator: Box::new(declarator), initializer: Some(initializer) diff --git a/src/ast2/context.rs b/src/ast2/context.rs index 9754ae3..055cf17 100644 --- a/src/ast2/context.rs +++ b/src/ast2/context.rs @@ -18,6 +18,7 @@ use super::StmtSwitchCase; use super::StmtVariableDeclaration; use super::StorageQualifier; use super::StructType; +use super::TranslationUnit; use super::VariableInfo; use crate::ast; @@ -222,6 +223,19 @@ impl Context { self.function_scope.is_some() } + pub fn process_translation_unit( + &mut self, + tu: ast::TranslationUnit, + ) -> Result { + let mut statements = Vec::new(); + + for item in tu.statements.into_iter() { + let statement = self.process_statement(item)?; + statements.push(statement); + } + + Ok(TranslationUnit { statements }) + } pub fn process_statement( &mut self, statement: ast::Statement, @@ -569,7 +583,7 @@ impl Context { ) -> Result { // @TODO storage_qualifier check // currently ignore all storage qualifiers - let (storage_qualifier, base_type) = self.process_decl_specs(stmt.specs.into_iter())?; + let (_storage_qualifier, base_type) = self.process_decl_specs(stmt.specs.into_iter())?; match stmt.inits { Some(decl_inits) => { @@ -733,7 +747,7 @@ impl Context { // type name `name` exists. // check if it's struct declaration of same type - let PrimitiveType::Struct(other_struct_def) = &old.type_ + let PrimitiveType::Struct(_other_struct_def) = &old.type_ else { // it is not struct, // redifinition of type name `name` @@ -756,7 +770,7 @@ impl Context { // type name `name` exists. // check if it's struct declaration of same type - let PrimitiveType::Struct(other_struct_def) = &old.type_ + let PrimitiveType::Struct(_other_struct_def) = &old.type_ else { // it is not struct, // redifinition of type name `name` @@ -858,7 +872,7 @@ impl Context { // type name `name` exists. // check if it's union declaration of same type - let PrimitiveType::Union(other_union_def) = &old.type_ + let PrimitiveType::Union(_other_union_def) = &old.type_ else { // it is not union, // redifinition of type name `name` @@ -881,7 +895,7 @@ impl Context { // type name `name` exists. // check if it's union declaration of same type - let PrimitiveType::Union(other_union_def) = &old.type_ + let PrimitiveType::Union(_other_union_def) = &old.type_ else { // it is not union, // redifinition of type name `name` @@ -985,7 +999,8 @@ impl Context { // type name `name` exists. // check if it's enum declaration of same type - let PrimitiveType::Enum(other_enum_def) = &old.type_ else { + let PrimitiveType::Enum(_other_enum_def) = &old.type_ + else { // it is not enum, // redifinition of type name `name` return Err(CompileError::TypeRedifinition(name)); @@ -1008,7 +1023,8 @@ impl Context { // type name `name` exists. // check if it's enum declaration of same type - let PrimitiveType::Enum(other_enum_def) = &old.type_ else { + let PrimitiveType::Enum(_other_enum_def) = &old.type_ + else { // it is not enum, // redifinition of type name `name` return Err(CompileError::TypeRedifinition(name)); @@ -1048,7 +1064,7 @@ impl Context { return Err(CompileError::NestedFunctionDefinition); } - let (storage_qualifier, base_type) = match stmt.specs { + let (_storage_qualifier, base_type) = match stmt.specs { Some(specs) => self.process_decl_specs(specs.into_iter())?, None => ( StorageQualifier::new(), @@ -1121,8 +1137,8 @@ impl Context { // for expressions impl Context { - pub fn expression_type(&self, expr: &Expression) -> CVType { - match expr { + pub fn expression_type(&self, expr: &Expression) -> Result { + Ok(match expr { Expression::Variable(var) => var.cv_type.clone(), Expression::I8(_) => CVType::from_primitive(PrimitiveType::Int8), Expression::I16(_) => CVType::from_primitive(PrimitiveType::Int16), @@ -1142,16 +1158,34 @@ impl Context { }))) } Expression::Cast(expr) => expr.type_.clone(), - Expression::Arrow(expr) => unimplemented!("expression_type Arrow"), - Expression::Bracket(expr) => unimplemented!("expression_type Bracket"), - Expression::Conditional(expr) => unimplemented!("expression_type Conditional"), + Expression::Bracket(expr) => match self.expression_type(&expr.src)?.type_ { + PrimitiveType::Pointer(t) => *t, + PrimitiveType::Array(t) => *t.cv_type, + _ => return Err(CompileError::BracketOnNonArrayOrPointer), + }, + Expression::Conditional(expr) => { + let cond_type = self.expression_type(&expr.cond)?.type_; + if cond_type.is_bool_castable() { + let then_type = self.expression_type(&expr.then_expr)?.type_; + let else_type = self.expression_type(&expr.else_expr)?.type_; + match then_type.common_type(&else_type) { + Some(t) => CVType::from_primitive(t), + None => return Err(CompileError::ConditionalTypeMismatch), + } + } else { + return Err(CompileError::ConditionalNotBool); + } + } Expression::InitializerList(expr) => unimplemented!("expression_type InitializerList"), - Expression::Paren(expr) => unimplemented!("expression_type Paren"), + Expression::Paren(expr) => match self.expression_type(&expr.src)?.type_ { + PrimitiveType::Function(func) => *func.return_type, + _ => return Err(CompileError::CallNonFunction), + }, Expression::Binary(expr) => unimplemented!("expression_type Binary"), Expression::Unary(expr) => unimplemented!("expression_type Unary"), Expression::Member(expr) => expr.member_type.clone(), Expression::Arrow(expr) => expr.member_type.clone(), - } + }) } pub(crate) fn process_expression_identifier( &mut self, @@ -1227,7 +1261,7 @@ impl Context { expr: ast::ExprMember, ) -> Result { let src = self.process_expression(*expr.src)?; - match self.expression_type(&src).type_ { + match self.expression_type(&src)?.type_ { PrimitiveType::Struct(s) | PrimitiveType::Union(s) => { let Some(body) = &s.body else { return Err(CompileError::MemberOnIncompleteType); @@ -1254,7 +1288,7 @@ impl Context { expr: ast::ExprArrow, ) -> Result { let src = self.process_expression(*expr.src)?; - let PrimitiveType::Pointer(src_type) = self.expression_type(&src).type_ else { + let PrimitiveType::Pointer(src_type) = self.expression_type(&src)?.type_ else { return Err(CompileError::ArrowOnNonPointer); }; match src_type.type_ { @@ -1284,12 +1318,12 @@ impl Context { expr: ast::ExprBracket, ) -> Result { let src = self.process_expression(*expr.src)?; - match self.expression_type(&src).type_ { + match self.expression_type(&src)?.type_ { PrimitiveType::Array(_) | PrimitiveType::Pointer(_) => {} _ => return Err(CompileError::BracketOnNonArrayOrPointer), } let index = self.process_expression(*expr.index)?; - if !self.expression_type(&index).type_.is_integer() { + if !self.expression_type(&index)?.type_.is_integer() { return Err(CompileError::BracketIndexNotInteger); } @@ -1302,9 +1336,15 @@ impl Context { &mut self, expr: ast::ExprParen, ) -> Result { - // @TODO callable check + let src = self.process_expression(*expr.src)?; + match self.expression_type(&src)?.type_ { + PrimitiveType::Function(_func_info) => { + // @TODO argument type, variadic check + } + _ => return Err(CompileError::CallNonFunction), + } Ok(Expression::Paren(expression::ExprParen { - src: Box::new(self.process_expression(*expr.src)?), + src: Box::new(src), args: expr .args .into_iter() @@ -1346,7 +1386,7 @@ impl Context { expr: ast::ExprSizeOfExpr, ) -> Result { let expr = self.process_expression(*expr.expr)?; - let typename = self.expression_type(&expr); + let typename = self.expression_type(&expr)?; Ok(Expression::U64(self.type_sizeof(&typename.type_)? as u64)) } pub(crate) fn process_expression_conditional( @@ -1445,7 +1485,7 @@ impl Context { pub(crate) fn process_specs( &mut self, - mut specs: impl Iterator, + specs: impl Iterator, ) -> Result { let mut collector = declarator::SpecifierQualifierCollector::new(); for s in specs { @@ -1464,8 +1504,32 @@ impl Context { ast::TypeSpecifier::Double => collector.set_double()?, ast::TypeSpecifier::Signed => collector.set_signed()?, ast::TypeSpecifier::Unsigned => collector.set_unsigned()?, - ast::TypeSpecifier::Typename(name) => unimplemented!("process_specs-typename"), - ast::TypeSpecifier::StructOrUnion(s) => unimplemented!("process_specs-struct"), + ast::TypeSpecifier::Typename(name) => { + let mut found = false; + for scope in self.scopes.iter().rev() { + if let Scope::Block(scope) = scope { + if let Some(typedef) = scope.typedefs.get(&name) { + collector.set_typename(typedef)?; + found = true; + break; + } + } + } + if !found { + if let Some(typedef) = self.global_scope.typedefs.get(&name) { + collector.set_typename(typedef)?; + } else { + return Err(CompileError::TypeNotFound(name)); + } + } + } + ast::TypeSpecifier::StructOrUnion(s) => { + if let Some(definition) = s.decls { + for def in definition.into_iter() {} + } else { + } + unimplemented!("process_specs-struct") + } ast::TypeSpecifier::Enum(e) => unimplemented!("process_specs-enum"), }, } @@ -1474,7 +1538,7 @@ impl Context { } pub(crate) fn process_decl_specs( &mut self, - mut specs: impl Iterator, + specs: impl Iterator, ) -> Result<(StorageQualifier, CVType), CompileError> { let mut storage_qualifier = StorageQualifier::new(); let mut collector = declarator::SpecifierQualifierCollector::new(); diff --git a/src/ast2/declarator.rs b/src/ast2/declarator.rs index bc9be95..19cd42b 100644 --- a/src/ast2/declarator.rs +++ b/src/ast2/declarator.rs @@ -1,5 +1,6 @@ use super::CVType; use super::CompileError; +use super::PrimitiveType; #[derive(Debug, Clone)] pub struct CombinedDeclarator { @@ -8,29 +9,86 @@ pub struct CombinedDeclarator { pub cv_type: CVType, } -pub(crate) struct SpecifierQualifierCollector {} +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum IntSizeSpecifier { + Char, + Short, + Int, +} +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum SignedSpecifier { + Signed, + Unsigned, +} +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum FloatSizeSpecifier { + Float, + Double, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) struct SpecifierQualifierCollector { + pub long: bool, + pub signed: Option, + pub int: Option, + pub float: Option, + pub const_: bool, + pub volatile: bool, + pub void: bool, + // pub struct_: Option, +} impl SpecifierQualifierCollector { pub fn new() -> Self { - Self {} + Self { + long: false, + signed: None, + int: None, + float: None, + const_: false, + volatile: false, + void: false, + // struct_: None, + } } pub fn set_const(&mut self) -> Result<(), CompileError> { - unimplemented!() + self.const_ = true; + Ok(()) } pub fn set_volatile(&mut self) -> Result<(), CompileError> { - unimplemented!() + self.volatile = true; + Ok(()) } pub fn set_int(&mut self) -> Result<(), CompileError> { - unimplemented!() + if let Some(old) = self.int { + if old != IntSizeSpecifier::Int { + return Err(CompileError::InvalidTypeSpecifier); + } + } + self.int = Some(IntSizeSpecifier::Int); + Ok(()) } pub fn set_char(&mut self) -> Result<(), CompileError> { - unimplemented!() + if let Some(old) = self.int { + if old != IntSizeSpecifier::Char { + return Err(CompileError::InvalidTypeSpecifier); + } + } + self.int = Some(IntSizeSpecifier::Char); + Ok(()) } pub fn set_short(&mut self) -> Result<(), CompileError> { - unimplemented!() + if let Some(old) = self.int { + if old != IntSizeSpecifier::Short { + return Err(CompileError::InvalidTypeSpecifier); + } + } + self.int = Some(IntSizeSpecifier::Short); + Ok(()) } pub fn set_long(&mut self) -> Result<(), CompileError> { - unimplemented!() + self.long = true; + Ok(()) } pub fn set_signed(&mut self) -> Result<(), CompileError> { unimplemented!() @@ -56,11 +114,32 @@ impl SpecifierQualifierCollector { pub fn set_enum(&mut self) -> Result<(), CompileError> { unimplemented!() } - pub fn set_typename(&mut self) -> Result<(), CompileError> { + pub fn set_typename(&mut self, cv_type: &CVType) -> Result<(), CompileError> { unimplemented!() } pub fn into_type(self) -> Result { - unimplemented!() + unimplemented!("SpecifierQualifierCollector::into_type") + /* + let base_type = if self.long { + match self.int { + Some(IntSizeSpecifier::Char) | Some(IntSizeSpecifier::Short) => { + return Err(CompileError::InvalidTypeSpecifier); + } + Some(IntSizeSpecifier::Int) | None => match self.signed { + Some(SignedSpecifier::Unsigned) => PrimitiveType::UInt64, + Some(SignedSpecifier::Signed) | None => PrimitiveType::Int64, + }, + _ => unreachable!(), + } + } else { + }; + + Ok(CVType { + const_: self.const_, + volatile: self.volatile, + type_: base_type, + }) + */ } } diff --git a/src/ast2/error.rs b/src/ast2/error.rs index f8bb915..d53218e 100644 --- a/src/ast2/error.rs +++ b/src/ast2/error.rs @@ -48,4 +48,13 @@ pub enum CompileError { MultipleFunctionDefinition(String), TypeRedifinition(String), + TypeNotFound(String), + + /// ex) `int short;`, `unsigned long signed;` invalid combination + InvalidTypeSpecifier, + + CallNonFunction, + + ConditionalTypeMismatch, + ConditionalNotBool, } diff --git a/src/ast2/mod.rs b/src/ast2/mod.rs index dc24037..45e4165 100644 --- a/src/ast2/mod.rs +++ b/src/ast2/mod.rs @@ -10,6 +10,7 @@ mod variable; pub use statement::Statement; pub use statement::StmtCompound; +pub use statement::StmtDoWhile; pub use statement::StmtExpression; pub use statement::StmtFor; pub use statement::StmtGoto; @@ -19,6 +20,8 @@ pub use statement::StmtReturn; pub use statement::StmtSwitch; pub use statement::StmtSwitchCase; pub use statement::StmtVariableDeclaration; +pub use statement::StmtWhile; +pub use statement::TranslationUnit; pub use expression::ExprBinary; pub use expression::ExprBinaryOp; diff --git a/src/ast2/statement.rs b/src/ast2/statement.rs index ce8a29e..180f1e4 100644 --- a/src/ast2/statement.rs +++ b/src/ast2/statement.rs @@ -103,3 +103,8 @@ pub struct StmtVariableDeclaration { /// (variable, initial value) pairs pub pairs: Vec<(VariableInfo, Expression)>, } + +#[derive(Debug, Clone)] +pub struct TranslationUnit { + pub statements: Vec, +} diff --git a/src/ast2/typename.rs b/src/ast2/typename.rs index 6d35a71..dde3228 100644 --- a/src/ast2/typename.rs +++ b/src/ast2/typename.rs @@ -52,6 +52,36 @@ impl PrimitiveType { pub fn is_float(&self) -> bool { matches!(self, PrimitiveType::Float32 | PrimitiveType::Float64) } + + pub fn is_bool_castable(&self) -> bool { + match self { + PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => true, + PrimitiveType::Enum(enum_type) => enum_type.type_.is_bool_castable(), + _ => false, + } + } + pub fn common_type(&self, other: &Self) -> Option { + unimplemented!("common_type") + // match (self, other) { + // (PrimitiveType::Void, _) | (_, PrimitiveType::Void) => None, + // (PrimitiveType::UInt8, PrimitiveType::UInt8) => Some(PrimitiveType::UInt8), + // (PrimitiveType::UInt16, PrimitiveType::UInt16) => Some(PrimitiveType::UInt16), + // (PrimitiveType::UInt32, PrimitiveType::UInt32) => Some(PrimitiveType::UInt32), + // (PrimitiveType::UInt64, PrimitiveType::UInt64) => Some(PrimitiveType::UInt64), + // (PrimitiveType::Int8, PrimitiveType::Int8) => Some(PrimitiveType::Int8), + + // } + // None + } } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] diff --git a/src/main.rs b/src/main.rs index 130dcf1..4d7505b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use std::io::{stdin, stdout, Read, Write}; -use virtualmachine::instruction::generation::InstructionGenerator; -use virtualmachine::program::VirtualMachine; +// use virtualmachine::instruction::generation::InstructionGenerator; +// use virtualmachine::program::VirtualMachine; mod ast; mod ast2; @@ -74,8 +74,21 @@ fn main() { // parse the tokens into AST println!("ASTs: "); - let parser = ast::parser::ASTParser::new(); - let translation_unit = parser.parse(tokens); + let parser = ast::translation_unitParser::new(); + let mut context = ast::translation_unitContext::new(); + for token in tokens.into_iter().chain(std::iter::once(token::Token::Eof)) { + match context.feed(&parser, token, &mut ()) { + Ok(_) => {} + Err(err) => { + println!("Error: {:?}", err); + break; + } + } + } + let translation_unit = context.accept(); + println!("{:#?}", translation_unit); + + /* println!("{:#?}", translation_unit); // generate instructions @@ -103,4 +116,5 @@ fn main() { vm.execute(&mut instructions); stdout().flush().expect("Failed to flush stdout"); + */ } diff --git a/src/virtualmachine/function.rs b/src/virtualmachine/function.rs deleted file mode 100644 index 8b13789..0000000 --- a/src/virtualmachine/function.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/virtualmachine/generator.rs b/src/virtualmachine/generator.rs new file mode 100644 index 0000000..f43ecc2 --- /dev/null +++ b/src/virtualmachine/generator.rs @@ -0,0 +1,160 @@ +use super::Instruction; +use super::LabelType; +use super::VirtualMachine; + +use crate::ast2; +use ast2::CompileError; +use ast2::Expression; +use ast2::Statement; +use ast2::VariableInfo; + +#[derive(Debug)] +pub struct InstructionGenerator { + /// generated instructions + pub instructions: Vec, + + /// label map + pub labels: Vec>, + /// label stack for continue, break + /// default, break for switch statement + pub label_stack: Vec<(LabelType, LabelType)>, + + /// where constant data is stored + /// for same-address system with stack data, it will be merged into stack upon program execution + /// + /// commonly, this is used for read-only data + /// but we don't have `const` qualifier yet + /// so it is mutable ... + pub text_section: Vec, +} +impl InstructionGenerator { + pub fn new() -> Self { + Self { + instructions: Vec::new(), + labels: Vec::new(), + label_stack: Vec::new(), + text_section: Vec::new(), + } + } + + fn generate_label(&mut self) -> LabelType { + let label = self.labels.len(); + self.labels.push(None); + label + } + /// link label name to current instruction address + fn set_label(&mut self, label: LabelType) { + let addr = self.instructions.len(); + self.labels[label] = Some(addr); + } + + pub fn process( + &mut self, + translation_unit: ast2::TranslationUnit, + ) -> Result { + for statement in translation_unit.statements { + self.process_statement(statement)?; + } + + let mut vm = VirtualMachine::new(); + vm.label_map = std::mem::take(&mut self.labels) + .into_iter() + .map(|x| x.unwrap()) + .collect(); + vm.instructions = std::mem::take(&mut self.instructions); + Ok(vm) + } + + pub fn process_statement(&mut self, statement: Statement) -> Result<(), CompileError> { + match statement { + Statement::None => {} + Statement::Expression(stmt) => self.process_statement_expression(stmt), + Statement::Labeled(stmt) => self.process_statement_labeled(stmt), + Statement::Goto(stmt) => self.process_statement_goto(stmt), + Statement::Compound(stmt) => self.process_statement_compound(stmt), + Statement::If(stmt) => self.process_statement_if(stmt), + Statement::Switch(stmt) => self.process_statement_switch(stmt), + Statement::_Case(_) => unreachable!("_Case should not be visible to end-users"), + Statement::_Default(_) => { + unreachable!("_Default should not be visible to end-users") + } + Statement::Continue => self.process_statement_continue(), + Statement::Break => self.process_statement_break(), + Statement::Return(stmt) => self.process_statement_return(stmt), + Statement::For(stmt) => self.process_statement_for(stmt), + Statement::While(stmt) => self.process_statement_while(stmt), + Statement::DoWhile(stmt) => self.process_statement_dowhile(stmt), + Statement::VariableDeclaration(stmt) => { + self.process_statement_variable_declaration(stmt) + } + } + Ok(()) + } + + pub fn process_expression(&mut self, expression: Expression) -> Result<(), CompileError> { + match expression { + Expression::I8(expr) => self.process_expression_i8(expr), + Expression::I16(expr) => self.process_expression_i16(expr), + Expression::I32(expr) => self.process_expression_i32(expr), + Expression::I64(expr) => self.process_expression_i64(expr), + Expression::U8(expr) => self.process_expression_u8(expr), + Expression::U16(expr) => self.process_expression_u16(expr), + Expression::U32(expr) => self.process_expression_u32(expr), + Expression::U64(expr) => self.process_expression_u64(expr), + Expression::F32(expr) => self.process_expression_f32(expr), + Expression::F64(expr) => self.process_expression_f64(expr), + Expression::String(expr) => self.process_expression_string(expr), + Expression::Variable(expr) => self.process_expression_variable(expr), + Expression::Conditional(expr) => self.process_expression_conditional(expr), + Expression::Cast(expr) => self.process_expression_cast(expr), + Expression::Member(expr) => self.process_expression_member(expr), + Expression::Arrow(expr) => self.process_expression_arrow(expr), + Expression::Paren(expr) => self.process_expression_paren(expr), + Expression::Bracket(expr) => self.process_expression_bracket(expr), + Expression::Unary(expr) => self.process_expression_unary(expr), + Expression::Binary(expr) => self.process_expression_binary(expr), + Expression::InitializerList(expr) => self.process_expression_initializerlist(expr), + } + Ok(()) + } +} + +impl InstructionGenerator { + fn process_statement_expression(&mut self, stmt: ast2::StmtExpression) {} + fn process_statement_labeled(&mut self, stmt: ast2::StmtLabeled) {} + fn process_statement_goto(&mut self, stmt: ast2::StmtGoto) {} + fn process_statement_compound(&mut self, stmt: ast2::StmtCompound) {} + fn process_statement_if(&mut self, stmt: ast2::StmtIf) {} + fn process_statement_switch(&mut self, stmt: ast2::StmtSwitch) {} + fn process_statement_continue(&mut self) {} + fn process_statement_break(&mut self) {} + fn process_statement_return(&mut self, stmt: ast2::StmtReturn) {} + fn process_statement_for(&mut self, stmt: ast2::StmtFor) {} + fn process_statement_while(&mut self, stmt: ast2::StmtWhile) {} + fn process_statement_dowhile(&mut self, stmt: ast2::StmtDoWhile) {} + fn process_statement_variable_declaration(&mut self, stmt: ast2::StmtVariableDeclaration) {} +} + +impl InstructionGenerator { + fn process_expression_i8(&mut self, expr: i8) {} + fn process_expression_i16(&mut self, expr: i16) {} + fn process_expression_i32(&mut self, expr: i32) {} + fn process_expression_i64(&mut self, expr: i64) {} + fn process_expression_u8(&mut self, expr: u8) {} + fn process_expression_u16(&mut self, expr: u16) {} + fn process_expression_u32(&mut self, expr: u32) {} + fn process_expression_u64(&mut self, expr: u64) {} + fn process_expression_f32(&mut self, expr: f32) {} + fn process_expression_f64(&mut self, expr: f64) {} + fn process_expression_string(&mut self, expr: String) {} + fn process_expression_variable(&mut self, expr: VariableInfo) {} + fn process_expression_conditional(&mut self, expr: ast2::ExprConditional) {} + fn process_expression_cast(&mut self, expr: ast2::ExprCast) {} + fn process_expression_member(&mut self, expr: ast2::ExprMember) {} + fn process_expression_arrow(&mut self, expr: ast2::ExprMember) {} + fn process_expression_paren(&mut self, expr: ast2::ExprParen) {} + fn process_expression_bracket(&mut self, expr: ast2::ExprBracket) {} + fn process_expression_unary(&mut self, expr: ast2::ExprUnary) {} + fn process_expression_binary(&mut self, expr: ast2::ExprBinary) {} + fn process_expression_initializerlist(&mut self, expr: ast2::ExprInitializerList) {} +} diff --git a/src/virtualmachine/instruction/mod.rs b/src/virtualmachine/instruction.rs similarity index 99% rename from src/virtualmachine/instruction/mod.rs rename to src/virtualmachine/instruction.rs index 688c493..b26009d 100644 --- a/src/virtualmachine/instruction/mod.rs +++ b/src/virtualmachine/instruction.rs @@ -1,15 +1,7 @@ -pub mod generation; -pub mod operand; - use super::program::{STACK_POINTER_BASE_REGISTER, STACK_POINTER_REGISTER, STACK_SIZE}; -use super::variable::VariableData; -use crate::ast::typename::TypeInfo; -use crate::virtualmachine::program::VirtualMachine; -use operand::*; #[derive(Debug, Clone)] pub enum Instruction { - DefineLabel(DefineLabel), MoveRegister(MoveRegister), PushStack(PushStack), PopStack(PopStack), diff --git a/src/virtualmachine/instruction/generation.rs b/src/virtualmachine/instruction/generation.rs deleted file mode 100644 index 38340c9..0000000 --- a/src/virtualmachine/instruction/generation.rs +++ /dev/null @@ -1,238 +0,0 @@ -use super::DefineLabel; -use super::Instruction; -use crate::ast::typename::TypeInfo; -use crate::virtualmachine::scope::*; -use std::collections::HashMap; - -#[derive(Debug, Clone)] -pub struct FunctionInfo { - pub return_type: TypeInfo, - pub params: Vec<(Option, TypeInfo)>, - pub is_defined: bool, -} - -/// return type for search_variable by name -#[derive(Debug, Clone, Copy)] -pub enum VariableOffset { - Global(usize), // absolute address in stack - Local(isize), // relative address from rbp -} - -#[derive(Debug)] -pub struct InstructionGenerator { - /// generated instructions - pub instructions: Vec, - - /// function map - pub functions: HashMap, - /// label map - pub labels: HashMap, - /// for label, anonymous name generation - pub unique_id: usize, - /// label stack for continue, break - /// default, break for switch statement - pub label_stack: Vec<(String, String)>, - - /// global variables must have absolute address in stack - /// local variables have relative address from rbp - pub global_scope: Scope, - - /// function may have multiple scopes inside. - /// we have to count the number of variable declaration - /// for stack allocation - pub function_scope: Option, - /// local variable scopes - pub scopes: Vec, - - /// start address of program - pub start_address: usize, - - /// where constant data is stored - /// for same-address system with stack data, it will be merged into stack upon program execution - /// - /// commonly, this is used for read-only data - /// but we don't have `const` qualifier yet - /// so it is mutable ... - pub text_section: Vec, -} -impl InstructionGenerator { - pub fn new() -> Self { - Self { - instructions: Vec::new(), - functions: HashMap::new(), - labels: HashMap::new(), - unique_id: 0, - start_address: 0, - scopes: Vec::new(), - function_scope: None, - global_scope: Scope::new(), - label_stack: Vec::new(), - text_section: Vec::new(), - } - } - /// push new instruction - pub fn push(&mut self, instruction: Instruction) { - self.instructions.push(instruction); - } - - /// for unique label generation - pub fn get_unique_id(&mut self) -> usize { - let ret = self.unique_id; - self.unique_id += 1; - ret - } - /// for unique label generation - pub fn get_unique_label(&mut self) -> String { - format!(".__L{}__", self.get_unique_id()) - } - - /// make new variable scopes - pub fn push_scope(&mut self) { - self.scopes.push(Scope::default()); - } - /// pop variable scopes - pub fn pop_scope(&mut self) { - self.scopes.pop().expect("pop_scope: no scope"); - } - - /// make new named variable on current scope - /// this does not allocate stack memory, just for variable counting - pub fn declare_variable(&mut self, name: &str, type_info: &TypeInfo, count: usize) { - let type_info = self.get_true_typeinfo(type_info); - // if there is function scope, it is local variable - let (offset, scope) = if let Some(func_scope) = &mut self.function_scope { - let offset = func_scope.declared_variable_count; - func_scope.declared_variable_count += count; - - func_scope.max_variable_count = func_scope - .max_variable_count - .max(func_scope.declared_variable_count); - - (offset, self.scopes.last_mut().unwrap()) - } else { - // if there is no function scope, it is global variable - let len = self.global_scope.variables.len(); - (len, &mut self.global_scope) - }; - let old = scope - .variables - .insert(name.to_string(), (type_info, offset as isize)); - if let Some(_) = old { - panic!("variable {} is already declared", name); - } - scope.declared_variable_count += count; - } - /// if variable's data is already in stack (e.g. function arguments) - /// this deos not count up variable_count - /// only for stack address-variable mapping - pub fn link_variable(&mut self, name: &str, type_info: &TypeInfo, offset_from_rbp: isize) { - let type_info = self.get_true_typeinfo(type_info); - let scope = self.scopes.last_mut().unwrap(); - let old = scope - .variables - .insert(name.to_string(), (type_info, offset_from_rbp)); - if let Some(_) = old { - panic!("variable {} is already declared", name); - } - } - /// search variable by name across scopes - pub fn search_variable(&self, name: &str) -> Option<(TypeInfo, VariableOffset)> { - for scope in self.scopes.iter().rev() { - if let Some((type_info, offset)) = scope.variables.get(name) { - return Some(( - self.get_true_typeinfo(type_info), - VariableOffset::Local(*offset as isize), - )); - } - } - if let Some((type_info, offset)) = self.global_scope.variables.get(name) { - return Some(( - self.get_true_typeinfo(type_info), - VariableOffset::Global(*offset as usize), - )); - } - None - } - /// search typeinfo by name across scopes - pub fn search_type(&self, name: &str) -> Option { - for scope in self.scopes.iter().rev() { - if let Some(type_info) = scope.type_infos.get(name) { - return Some(self.get_true_typeinfo(type_info)); - } - } - if let Some(type_info) = self.global_scope.type_infos.get(name) { - return Some(self.get_true_typeinfo(type_info)); - } - None - } - /// for struct type (and typedef-ed type in future) - /// there may be no field information in typeinfo ( `struct MyStruct a;` ) - /// so we need to find the definition of struct - pub fn get_true_typeinfo(&self, type_info: &TypeInfo) -> TypeInfo { - match type_info { - TypeInfo::Void - | TypeInfo::UInt8 - | TypeInfo::UInt16 - | TypeInfo::UInt32 - | TypeInfo::UInt64 - | TypeInfo::Int8 - | TypeInfo::Int16 - | TypeInfo::Int32 - | TypeInfo::Int64 - | TypeInfo::Float32 - | TypeInfo::Float64 - | TypeInfo::Pointer(_) => type_info.clone(), - TypeInfo::Array(t, len) => TypeInfo::Array(Box::new(self.get_true_typeinfo(t)), *len), - TypeInfo::Const(t) => TypeInfo::Const(Box::new(self.get_true_typeinfo(t))), - TypeInfo::Function(return_type, params) => { - let mut new_params = Vec::new(); - for t in params.iter() { - new_params.push(self.get_true_typeinfo(t)); - } - TypeInfo::Function(Box::new(self.get_true_typeinfo(return_type)), new_params) - } - - TypeInfo::Struct(sinfo) => { - if sinfo.fields.is_some() { - return type_info.clone(); - } - if sinfo.name.is_none() { - panic!("get_true_typeinfo: anonymous struct"); - } - - let searched = self.search_type(sinfo.name.as_ref().unwrap()).expect( - format!( - "get_true_typeinfo: struct {} is not defined", - sinfo.name.as_ref().unwrap() - ) - .as_str(), - ); - if let TypeInfo::Struct(sinfo) = searched { - return TypeInfo::Struct(sinfo.clone()); - } else { - panic!( - "get_true_typeinfo: {} is not struct", - sinfo.name.as_ref().unwrap() - ); - } - } - TypeInfo::Identifier(name) => self - .search_type(name) - .expect(format!("get_true_typeinfo: type {} is not defined", name).as_str()), - _ => panic!("get_true_typeinfo: not implemented {:?}", type_info), - } - } - - /// link label name to current instruction address - pub fn set_label(&mut self, label: &str) { - let old = self - .labels - .insert(label.to_string(), self.instructions.len()); - if let Some(_) = old { - panic!("label {} is already defined", label); - } - self.push(Instruction::DefineLabel(DefineLabel { - label: label.to_string(), - })); - } -} diff --git a/src/virtualmachine/mod.rs b/src/virtualmachine/mod.rs index 466d308..7bf47b0 100644 --- a/src/virtualmachine/mod.rs +++ b/src/virtualmachine/mod.rs @@ -1,5 +1,11 @@ -pub mod function; -pub mod instruction; -pub mod program; -pub mod scope; -pub mod variable; +mod generator; +mod instruction; +mod operand; +mod vm; + +pub type LabelType = usize; + +pub use instruction::Instruction; + +pub use generator::InstructionGenerator; +pub use vm::VirtualMachine; diff --git a/src/virtualmachine/instruction/operand.rs b/src/virtualmachine/operand.rs similarity index 96% rename from src/virtualmachine/instruction/operand.rs rename to src/virtualmachine/operand.rs index daf0232..bcec1c3 100644 --- a/src/virtualmachine/instruction/operand.rs +++ b/src/virtualmachine/operand.rs @@ -1,5 +1,5 @@ -use crate::virtualmachine::program::VirtualMachine; use crate::virtualmachine::variable::VariableData; +use crate::virtualmachine::vm::VirtualMachine; /// Type for Operand /// Derefed: [rax + offset] diff --git a/src/virtualmachine/program.rs b/src/virtualmachine/program.rs deleted file mode 100644 index 5c446ff..0000000 --- a/src/virtualmachine/program.rs +++ /dev/null @@ -1,78 +0,0 @@ -use super::variable::VariableData; - -use crate::virtualmachine::instruction::generation::InstructionGenerator; -use std::collections::HashMap; - -/// Virtual Program -/// have stack, registers, labels -pub struct VirtualMachine { - pub label_map: HashMap, - pub stack: Vec, - - /// size of text section - /// because we use front of stack for text section, we need offset for stack pointer - - /// each register is for single primitive type - /// rax, rbx, rcx, rdx, rtx, rbp, rsp - /// last tree registers are for - /// text section size, stack pointer and base pointer - pub registers: [VariableData; 7], - - pub current_instruction: usize, -} - -pub const STACK_SIZE: usize = 10240; // stack size -pub const STACK_POINTER_REGISTER: usize = 6; // index of register for use as stack pointer (rsp) -pub const STACK_POINTER_BASE_REGISTER: usize = 5; // index of register for use as stack base pointer (rbp) -pub const TEXT_SIZE_REGISTER: usize = 4; // index of register for use as text section size (rtx) -pub const RAX: usize = 0; // index of register for use as rax -pub const RBX: usize = 1; // index of register for use as rax -pub const RCX: usize = 2; // index of register for use as rax -pub const RDX: usize = 3; // index of register for use as rax -impl VirtualMachine { - pub fn new() -> VirtualMachine { - let mut ret = VirtualMachine { - label_map: HashMap::new(), - stack: Vec::new(), - - registers: [ - VariableData::UInt64(0), // rax - VariableData::UInt64(0), // rbx - VariableData::UInt64(0), // rcx - VariableData::UInt64(0), // rdx - VariableData::UInt64(0), // rtx - VariableData::UInt64(0), // rpb - VariableData::UInt64(0), // rsp - ], - - current_instruction: 0, - }; - // pre allocate stack - ret.stack.resize(STACK_SIZE, VariableData::UInt64(0)); - ret - } - - pub fn execute(&mut self, instructions: &InstructionGenerator) { - self.label_map = instructions.labels.clone(); - self.current_instruction = instructions.start_address; - - // set base pointer and stack pointer - self.registers[TEXT_SIZE_REGISTER] = - VariableData::UInt64(instructions.text_section.len() as u64); - self.registers[STACK_POINTER_REGISTER] = - VariableData::UInt64(instructions.text_section.len() as u64); - self.registers[STACK_POINTER_BASE_REGISTER] = - VariableData::UInt64(instructions.text_section.len() as u64); - - // copy text data to front of the stack - for (i, ch) in instructions.text_section.iter().enumerate() { - self.stack[i] = VariableData::Int8(*ch as i8); - } - - while self.current_instruction < instructions.instructions.len() { - instructions.instructions[self.current_instruction].execute(self); - - self.current_instruction += 1; - } - } -} diff --git a/src/virtualmachine/scope.rs b/src/virtualmachine/scope.rs deleted file mode 100644 index bf46875..0000000 --- a/src/virtualmachine/scope.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::ast::typename::TypeInfo; -use std::collections::HashMap; - -/// for variable scope -#[derive(Default, Debug)] -pub struct Scope { - // for typedef & declaration - pub type_infos: HashMap, - - // for variable declaration; (type, offset from rbp) - pub variables: HashMap, - - pub declared_variable_count: usize, -} -impl Scope { - pub fn new() -> Self { - Self { - type_infos: HashMap::new(), - variables: HashMap::new(), - declared_variable_count: 0, - } - } -} - -/// scope for function -/// this is not for variable mapping -/// but for variable counting; to track the number of variables alive -/// so need normal scope for variable declaration -#[derive(Debug, Default)] -pub struct FunctionScope { - pub declared_variable_count: usize, - pub max_variable_count: usize, -} -impl FunctionScope { - pub fn new() -> Self { - Self { - declared_variable_count: 0, - max_variable_count: 0, - } - } -} diff --git a/src/virtualmachine/vm.rs b/src/virtualmachine/vm.rs new file mode 100644 index 0000000..1b9a5a8 --- /dev/null +++ b/src/virtualmachine/vm.rs @@ -0,0 +1,40 @@ +use super::Instruction; + +/// Virtual Program +/// have stack, registers, labels +pub struct VirtualMachine { + pub(crate) label_map: Vec, + + pub(crate) stack: Vec, + + /// each register is for single primitive type + /// rax, rbx, rcx, rdx, rtx, rbp, rsp + /// last tree registers are for + /// text section size, stack pointer and base pointer + pub(crate) registers: [u64; 7], + + pub(crate) current_instruction: usize, + pub(crate) instructions: Vec, +} + +pub const STACK_SIZE: usize = 10240; // stack size +pub const STACK_POINTER_REGISTER: usize = 6; // index of register for use as stack pointer (rsp) +pub const STACK_POINTER_BASE_REGISTER: usize = 5; // index of register for use as stack base pointer (rbp) +pub const TEXT_SIZE_REGISTER: usize = 4; // index of register for use as text section size (rtx) +pub const RAX: usize = 0; // index of register for use as rax +pub const RBX: usize = 1; // index of register for use as rax +pub const RCX: usize = 2; // index of register for use as rax +pub const RDX: usize = 3; // index of register for use as rax +impl VirtualMachine { + pub fn new() -> VirtualMachine { + VirtualMachine { + label_map: Vec::new(), + stack: Vec::new(), + + registers: Default::default(), + + current_instruction: 0, + instructions: Vec::new(), + } + } +} From 9a287c89b514d31f74b9e4a6920489471dbf6411 Mon Sep 17 00:00:00 2001 From: Taehwan Kim Date: Thu, 31 Oct 2024 18:48:39 +0900 Subject: [PATCH 07/10] fix semicolon was not present in struct member declaration - struct and union definition - decl-specs collector --- src/ast/parser_lr.rs | 2 +- src/ast2/context.rs | 420 +++++++++++++++++++++--------- src/ast2/declarator.rs | 242 +++++++++++------ src/ast2/error.rs | 13 + src/ast2/expression.rs | 85 +++++- src/ast2/mod.rs | 2 + src/ast2/typename.rs | 124 +++++++++ src/ast2/variable.rs | 38 +++ src/main.rs | 12 +- src/virtualmachine/generator.rs | 221 ++++++++++------ src/virtualmachine/instruction.rs | 33 +-- 11 files changed, 894 insertions(+), 298 deletions(-) diff --git a/src/ast/parser_lr.rs b/src/ast/parser_lr.rs index cf6aa0b..6a8ec3f 100644 --- a/src/ast/parser_lr.rs +++ b/src/ast/parser_lr.rs @@ -1142,7 +1142,7 @@ struct_declarator_list( Vec ) ; struct_declaration( declarator::StructDeclaration ) - : specifier_qualifier+ struct_declarator_list { + : specifier_qualifier+ struct_declarator_list semicolon! { declarator::StructDeclaration { specs: specifier_qualifier, declarators: struct_declarator_list, diff --git a/src/ast2/context.rs b/src/ast2/context.rs index 055cf17..5711589 100644 --- a/src/ast2/context.rs +++ b/src/ast2/context.rs @@ -1,4 +1,5 @@ use std::cell::RefCell; +use std::collections::HashSet; use std::rc::Rc; use super::declarator; @@ -162,7 +163,7 @@ impl Context { fn begin_variable_scope( &mut self, name: String, - type_: CVType, + cv_type: CVType, ) -> Result { // search for `name` in current scope for scope in self.scopes.iter().rev() { @@ -176,13 +177,13 @@ impl Context { } } - let size = self.type_sizeof(&type_.type_)?; - let align = self.type_alignof(&type_.type_)?; + let size = cv_type.type_.sizeof()?; + let align = cv_type.type_.alignof()?; let offset = self.function_scope.as_mut().unwrap().pool.push(size, align); let varinfo = VariableInfo { name: name.clone(), address: Address::Local(offset), - cv_type: type_, + cv_type, }; let scope = VariableScope { name, @@ -635,8 +636,8 @@ impl Context { return Err(CompileError::MultipleVariableDefinition(name)); } - let size = self.type_sizeof(&init_type.cv_type.type_)?; - let align = self.type_alignof(&init_type.cv_type.type_)?; + let size = init_type.cv_type.type_.sizeof()?; + let align = init_type.cv_type.type_.alignof()?; let offset = self.global_scope.pool.push(size, align); let varinfo = VariableInfo { name: name.clone(), @@ -1137,56 +1138,6 @@ impl Context { // for expressions impl Context { - pub fn expression_type(&self, expr: &Expression) -> Result { - Ok(match expr { - Expression::Variable(var) => var.cv_type.clone(), - Expression::I8(_) => CVType::from_primitive(PrimitiveType::Int8), - Expression::I16(_) => CVType::from_primitive(PrimitiveType::Int16), - Expression::I32(_) => CVType::from_primitive(PrimitiveType::Int32), - Expression::I64(_) => CVType::from_primitive(PrimitiveType::Int64), - Expression::U8(_) => CVType::from_primitive(PrimitiveType::UInt8), - Expression::U16(_) => CVType::from_primitive(PrimitiveType::UInt16), - Expression::U32(_) => CVType::from_primitive(PrimitiveType::UInt32), - Expression::U64(_) => CVType::from_primitive(PrimitiveType::UInt64), - Expression::F32(_) => CVType::from_primitive(PrimitiveType::Float32), - Expression::F64(_) => CVType::from_primitive(PrimitiveType::Float64), - Expression::String(_) => { - CVType::from_primitive(PrimitiveType::Pointer(Box::new(CVType { - type_: PrimitiveType::Int8, - const_: true, - volatile: false, - }))) - } - Expression::Cast(expr) => expr.type_.clone(), - Expression::Bracket(expr) => match self.expression_type(&expr.src)?.type_ { - PrimitiveType::Pointer(t) => *t, - PrimitiveType::Array(t) => *t.cv_type, - _ => return Err(CompileError::BracketOnNonArrayOrPointer), - }, - Expression::Conditional(expr) => { - let cond_type = self.expression_type(&expr.cond)?.type_; - if cond_type.is_bool_castable() { - let then_type = self.expression_type(&expr.then_expr)?.type_; - let else_type = self.expression_type(&expr.else_expr)?.type_; - match then_type.common_type(&else_type) { - Some(t) => CVType::from_primitive(t), - None => return Err(CompileError::ConditionalTypeMismatch), - } - } else { - return Err(CompileError::ConditionalNotBool); - } - } - Expression::InitializerList(expr) => unimplemented!("expression_type InitializerList"), - Expression::Paren(expr) => match self.expression_type(&expr.src)?.type_ { - PrimitiveType::Function(func) => *func.return_type, - _ => return Err(CompileError::CallNonFunction), - }, - Expression::Binary(expr) => unimplemented!("expression_type Binary"), - Expression::Unary(expr) => unimplemented!("expression_type Unary"), - Expression::Member(expr) => expr.member_type.clone(), - Expression::Arrow(expr) => expr.member_type.clone(), - }) - } pub(crate) fn process_expression_identifier( &mut self, expr: ast::ExprIdentifier, @@ -1261,7 +1212,7 @@ impl Context { expr: ast::ExprMember, ) -> Result { let src = self.process_expression(*expr.src)?; - match self.expression_type(&src)?.type_ { + match src.cv_type()?.type_ { PrimitiveType::Struct(s) | PrimitiveType::Union(s) => { let Some(body) = &s.body else { return Err(CompileError::MemberOnIncompleteType); @@ -1288,7 +1239,7 @@ impl Context { expr: ast::ExprArrow, ) -> Result { let src = self.process_expression(*expr.src)?; - let PrimitiveType::Pointer(src_type) = self.expression_type(&src)?.type_ else { + let PrimitiveType::Pointer(src_type) = src.cv_type()?.type_ else { return Err(CompileError::ArrowOnNonPointer); }; match src_type.type_ { @@ -1318,12 +1269,12 @@ impl Context { expr: ast::ExprBracket, ) -> Result { let src = self.process_expression(*expr.src)?; - match self.expression_type(&src)?.type_ { + match src.cv_type()?.type_ { PrimitiveType::Array(_) | PrimitiveType::Pointer(_) => {} _ => return Err(CompileError::BracketOnNonArrayOrPointer), } let index = self.process_expression(*expr.index)?; - if !self.expression_type(&index)?.type_.is_integer() { + if !index.cv_type()?.type_.is_integer() { return Err(CompileError::BracketIndexNotInteger); } @@ -1337,7 +1288,7 @@ impl Context { expr: ast::ExprParen, ) -> Result { let src = self.process_expression(*expr.src)?; - match self.expression_type(&src)?.type_ { + match src.cv_type()?.type_ { PrimitiveType::Function(_func_info) => { // @TODO argument type, variadic check } @@ -1379,15 +1330,15 @@ impl Context { } else { base_type }; - Ok(Expression::U64(self.type_sizeof(&typename.type_)? as u64)) + Ok(Expression::U64(typename.type_.sizeof()? as u64)) } pub(crate) fn process_expression_sizeofexpr( &mut self, expr: ast::ExprSizeOfExpr, ) -> Result { let expr = self.process_expression(*expr.expr)?; - let typename = self.expression_type(&expr)?; - Ok(Expression::U64(self.type_sizeof(&typename.type_)? as u64)) + let typename = expr.cv_type()?; + Ok(Expression::U64(typename.type_.sizeof()? as u64)) } pub(crate) fn process_expression_conditional( &mut self, @@ -1442,47 +1393,6 @@ impl Context { // for declarators impl Context { - pub fn type_sizeof(&self, typename: &PrimitiveType) -> Result { - Ok(match typename { - PrimitiveType::Void => return Err(CompileError::SizeofIncompleteType), - PrimitiveType::UInt8 | PrimitiveType::Int8 => 1, - PrimitiveType::UInt16 | PrimitiveType::Int16 => 2, - PrimitiveType::UInt32 | PrimitiveType::Int32 | PrimitiveType::Float32 => 4, - PrimitiveType::UInt64 | PrimitiveType::Int64 | PrimitiveType::Float64 => 8, - PrimitiveType::Pointer(_) => 8, - PrimitiveType::Array(ArrayType { - cv_type: type_, - size, - }) => self.type_sizeof(&type_.type_)? * (*size), - PrimitiveType::Function(_) => return Err(CompileError::SizeofIncompleteType), - PrimitiveType::Struct(s) | PrimitiveType::Union(s) => match &s.body { - Some(s) => s.size, - None => return Err(CompileError::SizeofIncompleteType), - }, - PrimitiveType::Enum(e) => self.type_sizeof(&e.type_)?, - }) - } - pub fn type_alignof(&self, typename: &PrimitiveType) -> Result { - Ok(match typename { - PrimitiveType::Void => return Err(CompileError::SizeofIncompleteType), - PrimitiveType::UInt8 | PrimitiveType::Int8 => 1, - PrimitiveType::UInt16 | PrimitiveType::Int16 => 2, - PrimitiveType::UInt32 | PrimitiveType::Int32 | PrimitiveType::Float32 => 4, - PrimitiveType::UInt64 | PrimitiveType::Int64 | PrimitiveType::Float64 => 8, - PrimitiveType::Pointer(_) => 8, - PrimitiveType::Array(ArrayType { - cv_type: type_, - size: _, - }) => self.type_alignof(&type_.type_)?, - PrimitiveType::Function(_) => return Err(CompileError::SizeofIncompleteType), - PrimitiveType::Struct(s) | PrimitiveType::Union(s) => match &s.body { - Some(s) => s.align, - None => return Err(CompileError::AlignofIncompleteType), - }, - PrimitiveType::Enum(e) => self.type_alignof(&e.type_)?, - }) - } - pub(crate) fn process_specs( &mut self, specs: impl Iterator, @@ -1509,7 +1419,7 @@ impl Context { for scope in self.scopes.iter().rev() { if let Scope::Block(scope) = scope { if let Some(typedef) = scope.typedefs.get(&name) { - collector.set_typename(typedef)?; + collector.set_typename(typedef.clone())?; found = true; break; } @@ -1517,7 +1427,7 @@ impl Context { } if !found { if let Some(typedef) = self.global_scope.typedefs.get(&name) { - collector.set_typename(typedef)?; + collector.set_typename(typedef.clone())?; } else { return Err(CompileError::TypeNotFound(name)); } @@ -1525,12 +1435,129 @@ impl Context { } ast::TypeSpecifier::StructOrUnion(s) => { if let Some(definition) = s.decls { - for def in definition.into_iter() {} + let mut names = HashSet::new(); + let mut members = Vec::new(); + for def in definition.into_iter() { + let base_type = self.process_specs(def.specs.into_iter())?; + for decl in def.declarators.into_iter() { + let d = self.process_declarator(decl, base_type.clone())?; + let Some(name) = d.name else { + return Err(CompileError::DeclarationWithoutName); + }; + if names.insert(name.clone()) == false { + return Err(CompileError::MemberRedefined(name)); + } + + members.push((name, d.cv_type)); + } + } + let struct_type = if s.is_struct { + let struct_type = StructType::struct_from_decls(s.name, members); + CVType::from_primitive(PrimitiveType::Struct(struct_type)) + } else { + let union_type = StructType::union_from_decls(s.name, members); + CVType::from_primitive(PrimitiveType::Union(union_type)) + }; + collector.set_typename(struct_type)?; + } else { + let Some(name) = s.name else { + return Err(CompileError::IncompleteType); + }; + + // search for type definition `name` + let mut found = false; + for scope in self.scopes.iter().rev() { + if let Scope::Block(scope) = scope { + if let Some(typedef) = scope.typedefs.get(&name) { + if s.is_struct && !typedef.type_.is_struct() { + return Err(CompileError::StructMismatch(name)); + } + if !s.is_struct && !typedef.type_.is_union() { + return Err(CompileError::UnionMismatch(name)); + } + collector.set_typename(typedef.clone())?; + found = true; + break; + } + } + } + if !found { + if let Some(typedef) = self.global_scope.typedefs.get(&name) { + if s.is_struct && !typedef.type_.is_struct() { + return Err(CompileError::StructMismatch(name)); + } + if !s.is_struct && !typedef.type_.is_union() { + return Err(CompileError::UnionMismatch(name)); + } + collector.set_typename(typedef.clone())?; + } else { + return Err(CompileError::TypeNotFound(name)); + } + } + } + } + ast::TypeSpecifier::Enum(e) => { + if let Some(definition) = e.enumerators { + let mut names = HashSet::new(); + let mut members = Vec::new(); + for def in definition.into_iter() { + if names.insert(def.name.clone()) == false { + return Err(CompileError::MemberRedefined(def.name)); + } + + if let Some(expr) = def.value { + let expr = self.process_expression(expr)?; + let value = match expr { + Expression::I8(v) => v as i64, + Expression::I16(v) => v as i64, + Expression::I32(v) => v as i64, + Expression::I64(v) => v, + Expression::U8(v) => v as i64, + Expression::U16(v) => v as i64, + Expression::U32(v) => v as i64, + Expression::U64(v) => v as i64, + _ => return Err(CompileError::ArraySizeNotInteger), + }; + members.push((def.name, Some(value))); + } else { + members.push((def.name, None)); + } + } + let enum_type = EnumType::enum_from_decls(e.name, members); + let enum_type = PrimitiveType::Enum(enum_type); + let enum_type = CVType::from_primitive(enum_type); + collector.set_typename(enum_type)?; } else { + let Some(name) = e.name else { + return Err(CompileError::IncompleteType); + }; + + // search for type definition `name` + let mut found = false; + for scope in self.scopes.iter().rev() { + if let Scope::Block(scope) = scope { + if let Some(typedef) = scope.typedefs.get(&name) { + if !typedef.type_.is_enum() { + return Err(CompileError::EnumMismatch(name)); + } + collector.set_typename(typedef.clone())?; + found = true; + break; + } + } + } + if !found { + if let Some(typedef) = self.global_scope.typedefs.get(&name) { + if !typedef.type_.is_enum() { + return Err(CompileError::EnumMismatch(name)); + } + collector.set_typename(typedef.clone())?; + } else { + return Err(CompileError::TypeNotFound(name)); + } + } } - unimplemented!("process_specs-struct") } - ast::TypeSpecifier::Enum(e) => unimplemented!("process_specs-enum"), }, } } @@ -1567,12 +1594,149 @@ impl Context { ast::TypeSpecifier::Signed => collector.set_signed()?, ast::TypeSpecifier::Unsigned => collector.set_unsigned()?, ast::TypeSpecifier::Typename(name) => { - unimplemented!("process_decl_specs-typename") + let mut found = false; + for scope in self.scopes.iter().rev() { + if let Scope::Block(scope) = scope { + if let Some(typedef) = scope.typedefs.get(&name) { + collector.set_typename(typedef.clone())?; + found = true; + break; + } + } + } + if !found { + if let Some(typedef) = self.global_scope.typedefs.get(&name) { + collector.set_typename(typedef.clone())?; + } else { + return Err(CompileError::TypeNotFound(name)); + } + } } ast::TypeSpecifier::StructOrUnion(s) => { - unimplemented!("process_decl_specs-struct") + if let Some(definition) = s.decls { + let mut names = HashSet::new(); + let mut members = Vec::new(); + for def in definition.into_iter() { + let base_type = self.process_specs(def.specs.into_iter())?; + for decl in def.declarators.into_iter() { + let d = self.process_declarator(decl, base_type.clone())?; + let Some(name) = d.name else { + return Err(CompileError::DeclarationWithoutName); + }; + if names.insert(name.clone()) == false { + return Err(CompileError::MemberRedefined(name)); + } + + members.push((name, d.cv_type)); + } + } + let struct_type = if s.is_struct { + let struct_type = StructType::struct_from_decls(s.name, members); + CVType::from_primitive(PrimitiveType::Struct(struct_type)) + } else { + let union_type = StructType::union_from_decls(s.name, members); + CVType::from_primitive(PrimitiveType::Union(union_type)) + }; + collector.set_typename(struct_type)?; + } else { + let Some(name) = s.name else { + return Err(CompileError::IncompleteType); + }; + + // search for type definition `name` + let mut found = false; + for scope in self.scopes.iter().rev() { + if let Scope::Block(scope) = scope { + if let Some(typedef) = scope.typedefs.get(&name) { + if s.is_struct && !typedef.type_.is_struct() { + return Err(CompileError::StructMismatch(name)); + } + if !s.is_struct && !typedef.type_.is_union() { + return Err(CompileError::UnionMismatch(name)); + } + collector.set_typename(typedef.clone())?; + found = true; + break; + } + } + } + if !found { + if let Some(typedef) = self.global_scope.typedefs.get(&name) { + if s.is_struct && !typedef.type_.is_struct() { + return Err(CompileError::StructMismatch(name)); + } + if !s.is_struct && !typedef.type_.is_union() { + return Err(CompileError::UnionMismatch(name)); + } + collector.set_typename(typedef.clone())?; + } else { + return Err(CompileError::TypeNotFound(name)); + } + } + } + } + ast::TypeSpecifier::Enum(e) => { + if let Some(definition) = e.enumerators { + let mut names = HashSet::new(); + let mut members = Vec::new(); + for def in definition.into_iter() { + if names.insert(def.name.clone()) == false { + return Err(CompileError::MemberRedefined(def.name)); + } + + if let Some(expr) = def.value { + let expr = self.process_expression(expr)?; + let value = match expr { + Expression::I8(v) => v as i64, + Expression::I16(v) => v as i64, + Expression::I32(v) => v as i64, + Expression::I64(v) => v, + Expression::U8(v) => v as i64, + Expression::U16(v) => v as i64, + Expression::U32(v) => v as i64, + Expression::U64(v) => v as i64, + _ => return Err(CompileError::ArraySizeNotInteger), + }; + members.push((def.name, Some(value))); + } else { + members.push((def.name, None)); + } + } + let enum_type = EnumType::enum_from_decls(e.name, members); + let enum_type = PrimitiveType::Enum(enum_type); + let enum_type = CVType::from_primitive(enum_type); + collector.set_typename(enum_type)?; + } else { + let Some(name) = e.name else { + return Err(CompileError::IncompleteType); + }; + + // search for type definition `name` + let mut found = false; + for scope in self.scopes.iter().rev() { + if let Scope::Block(scope) = scope { + if let Some(typedef) = scope.typedefs.get(&name) { + if !typedef.type_.is_enum() { + return Err(CompileError::EnumMismatch(name)); + } + collector.set_typename(typedef.clone())?; + found = true; + break; + } + } + } + if !found { + if let Some(typedef) = self.global_scope.typedefs.get(&name) { + if !typedef.type_.is_enum() { + return Err(CompileError::EnumMismatch(name)); + } + collector.set_typename(typedef.clone())?; + } else { + return Err(CompileError::TypeNotFound(name)); + } + } + } } - ast::TypeSpecifier::Enum(e) => unimplemented!("process_decl_specs-enum"), }, } } @@ -1693,14 +1857,28 @@ impl Context { .collect::, _>>()?; let variadic = decl.params.variadic; - unimplemented!("process_declarator_function") - - // if let Some(decl) = decl.declarator { - // let res = self.process_declarator(*decl, base_type)?; - // FunctionType { args, variadic, - // } else { - // FunctionType { args, variadic, - // } + if let Some(decl) = decl.declarator { + let res = self.process_declarator(*decl, base_type)?; + let func_type = FunctionType { + args, + variadic, + return_type: Box::new(res.cv_type), + }; + Ok(CombinedDeclarator { + cv_type: CVType::from_primitive(PrimitiveType::Function(func_type)), + name: res.name, + }) + } else { + let func_type = FunctionType { + args, + variadic, + return_type: Box::new(base_type), + }; + Ok(CombinedDeclarator { + cv_type: CVType::from_primitive(PrimitiveType::Function(func_type)), + name: None, + }) + } } pub(crate) fn process_declarator_const( &mut self, diff --git a/src/ast2/declarator.rs b/src/ast2/declarator.rs index 19cd42b..4080887 100644 --- a/src/ast2/declarator.rs +++ b/src/ast2/declarator.rs @@ -9,137 +9,223 @@ pub struct CombinedDeclarator { pub cv_type: CVType, } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum IntSizeSpecifier { - Char, - Short, - Int, -} -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum SignedSpecifier { - Signed, - Unsigned, -} -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum FloatSizeSpecifier { - Float, - Double, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub(crate) struct SpecifierQualifierCollector { - pub long: bool, - pub signed: Option, - pub int: Option, - pub float: Option, pub const_: bool, pub volatile: bool, + pub void: bool, - // pub struct_: Option, + + pub unsigned: bool, + pub signed: bool, + + pub int: bool, + pub char: bool, + pub short: bool, + pub long: bool, + + pub float: bool, + pub double: bool, + + pub type_: Option, } impl SpecifierQualifierCollector { pub fn new() -> Self { Self { - long: false, - signed: None, - int: None, - float: None, const_: false, volatile: false, + void: false, - // struct_: None, + + unsigned: false, + signed: false, + + int: false, + char: false, + short: false, + long: false, + + float: false, + double: false, + + type_: None, } } pub fn set_const(&mut self) -> Result<(), CompileError> { + if self.void { + return Err(CompileError::InvalidTypeSpecifier); + } self.const_ = true; Ok(()) } pub fn set_volatile(&mut self) -> Result<(), CompileError> { + if self.void { + return Err(CompileError::InvalidTypeSpecifier); + } self.volatile = true; Ok(()) } pub fn set_int(&mut self) -> Result<(), CompileError> { - if let Some(old) = self.int { - if old != IntSizeSpecifier::Int { - return Err(CompileError::InvalidTypeSpecifier); - } + if self.void || self.char || self.float || self.double || self.type_.is_some() { + return Err(CompileError::InvalidTypeSpecifier); } - self.int = Some(IntSizeSpecifier::Int); + self.int = true; Ok(()) } pub fn set_char(&mut self) -> Result<(), CompileError> { - if let Some(old) = self.int { - if old != IntSizeSpecifier::Char { - return Err(CompileError::InvalidTypeSpecifier); - } + if self.void + || self.int + || self.short + || self.long + || self.float + || self.double + || self.type_.is_some() + { + return Err(CompileError::InvalidTypeSpecifier); } - self.int = Some(IntSizeSpecifier::Char); + self.char = true; Ok(()) } pub fn set_short(&mut self) -> Result<(), CompileError> { - if let Some(old) = self.int { - if old != IntSizeSpecifier::Short { - return Err(CompileError::InvalidTypeSpecifier); - } + if self.void || self.char || self.long || self.float || self.double || self.type_.is_some() + { + return Err(CompileError::InvalidTypeSpecifier); } - self.int = Some(IntSizeSpecifier::Short); + self.short = true; Ok(()) } pub fn set_long(&mut self) -> Result<(), CompileError> { + if self.void || self.char || self.short || self.float || self.double || self.type_.is_some() + { + return Err(CompileError::InvalidTypeSpecifier); + } self.long = true; Ok(()) } pub fn set_signed(&mut self) -> Result<(), CompileError> { - unimplemented!() + if self.void || self.signed || self.float || self.double || self.type_.is_some() { + return Err(CompileError::InvalidTypeSpecifier); + } + self.signed = true; + Ok(()) } pub fn set_unsigned(&mut self) -> Result<(), CompileError> { - unimplemented!() + if self.void || self.signed || self.float || self.double || self.type_.is_some() { + return Err(CompileError::InvalidTypeSpecifier); + } + self.unsigned = true; + Ok(()) } pub fn set_float(&mut self) -> Result<(), CompileError> { - unimplemented!() + if self.void + || self.unsigned + || self.signed + || self.int + || self.char + || self.short + || self.long + || self.double + || self.type_.is_some() + { + return Err(CompileError::InvalidTypeSpecifier); + } + self.float = true; + Ok(()) } pub fn set_double(&mut self) -> Result<(), CompileError> { - unimplemented!() + if self.void + || self.unsigned + || self.signed + || self.int + || self.char + || self.short + || self.long + || self.float + || self.type_.is_some() + { + return Err(CompileError::InvalidTypeSpecifier); + } + self.double = true; + Ok(()) } pub fn set_void(&mut self) -> Result<(), CompileError> { - unimplemented!() - } - pub fn set_struct(&mut self) -> Result<(), CompileError> { - unimplemented!() - } - pub fn set_union(&mut self) -> Result<(), CompileError> { - unimplemented!() - } - pub fn set_enum(&mut self) -> Result<(), CompileError> { - unimplemented!() + if self.const_ + || self.volatile + || self.unsigned + || self.signed + || self.int + || self.char + || self.short + || self.long + || self.float + || self.double + || self.type_.is_some() + { + return Err(CompileError::InvalidTypeSpecifier); + } + self.void = true; + Ok(()) } - pub fn set_typename(&mut self, cv_type: &CVType) -> Result<(), CompileError> { - unimplemented!() + pub fn set_typename(&mut self, cv_type: CVType) -> Result<(), CompileError> { + if self.void + || self.unsigned + || self.signed + || self.int + || self.char + || self.short + || self.long + || self.float + || self.double + || self.type_.is_some() + { + return Err(CompileError::InvalidTypeSpecifier); + } + self.type_ = Some(cv_type); + Ok(()) } pub fn into_type(self) -> Result { - unimplemented!("SpecifierQualifierCollector::into_type") - /* - let base_type = if self.long { - match self.int { - Some(IntSizeSpecifier::Char) | Some(IntSizeSpecifier::Short) => { - return Err(CompileError::InvalidTypeSpecifier); + let mut base_type = { + if self.void { + CVType::from_primitive(PrimitiveType::Void) + } else if self.float { + CVType::from_primitive(PrimitiveType::Float32) + } else if self.double { + CVType::from_primitive(PrimitiveType::Float64) + } else if self.char { + if self.unsigned { + CVType::from_primitive(PrimitiveType::UInt8) + } else { + CVType::from_primitive(PrimitiveType::Int8) + } + } else if self.short { + if self.unsigned { + CVType::from_primitive(PrimitiveType::UInt16) + } else { + CVType::from_primitive(PrimitiveType::Int16) + } + } else if self.long { + if self.unsigned { + CVType::from_primitive(PrimitiveType::UInt64) + } else { + CVType::from_primitive(PrimitiveType::Int64) + } + } else if self.int { + if self.unsigned { + CVType::from_primitive(PrimitiveType::UInt32) + } else { + CVType::from_primitive(PrimitiveType::Int32) + } + } else { + match self.type_ { + Some(t) => t, + None => return Err(CompileError::InvalidTypeSpecifier), } - Some(IntSizeSpecifier::Int) | None => match self.signed { - Some(SignedSpecifier::Unsigned) => PrimitiveType::UInt64, - Some(SignedSpecifier::Signed) | None => PrimitiveType::Int64, - }, - _ => unreachable!(), } - } else { }; - - Ok(CVType { - const_: self.const_, - volatile: self.volatile, - type_: base_type, - }) - */ + base_type.const_ = self.const_; + base_type.volatile = self.volatile; + Ok(base_type) } } diff --git a/src/ast2/error.rs b/src/ast2/error.rs index d53218e..da8f5d0 100644 --- a/src/ast2/error.rs +++ b/src/ast2/error.rs @@ -21,9 +21,22 @@ pub enum CompileError { DeclarationWithoutName, + /// same member name in struct or union or enum + MemberRedefined(String), + BracketOnNonArrayOrPointer, BracketIndexNotInteger, + /// variable declaration incomplete type + IncompleteType, + + /// use 'struct A' but A is not struct + StructMismatch(String), + /// use 'union A' but A is not union + UnionMismatch(String), + /// use 'enum A' but A is not enum + EnumMismatch(String), + SizeofIncompleteType, AlignofIncompleteType, diff --git a/src/ast2/expression.rs b/src/ast2/expression.rs index b15dec3..d327ee8 100644 --- a/src/ast2/expression.rs +++ b/src/ast2/expression.rs @@ -1,5 +1,7 @@ use crate::ast; +use super::CompileError; +use super::PrimitiveType; use super::{CVType, VariableInfo}; #[derive(Debug, Clone)] @@ -29,7 +31,88 @@ pub enum Expression { Binary(ExprBinary), InitializerList(ExprInitializerList), } -impl Expression {} +impl Expression { + /// is this expression returns an address upon generating instructions? + pub fn is_address(&self) -> bool { + match self { + Expression::I8(_) + | Expression::I16(_) + | Expression::I32(_) + | Expression::I64(_) + | Expression::U8(_) + | Expression::U16(_) + | Expression::U32(_) + | Expression::U64(_) + | Expression::F32(_) + | Expression::F64(_) => false, + Expression::String(_) => unimplemented!("is_address - String literal"), + Expression::Variable(_) => true, + Expression::Conditional(_) => false, + Expression::Cast(_) => false, + Expression::Member(_) => true, + Expression::Arrow(_) => true, + Expression::Paren(_) => false, + Expression::Bracket(_) => true, + Expression::Unary(expr) => match expr.op { + _ => false, + }, + Expression::Binary(_) => false, + Expression::InitializerList(_) => false, + } + } + + pub fn cv_type(&self) -> Result { + Ok(match self { + Expression::Variable(var) => var.cv_type.clone(), + Expression::I8(_) => CVType::from_primitive(PrimitiveType::Int8), + Expression::I16(_) => CVType::from_primitive(PrimitiveType::Int16), + Expression::I32(_) => CVType::from_primitive(PrimitiveType::Int32), + Expression::I64(_) => CVType::from_primitive(PrimitiveType::Int64), + Expression::U8(_) => CVType::from_primitive(PrimitiveType::UInt8), + Expression::U16(_) => CVType::from_primitive(PrimitiveType::UInt16), + Expression::U32(_) => CVType::from_primitive(PrimitiveType::UInt32), + Expression::U64(_) => CVType::from_primitive(PrimitiveType::UInt64), + Expression::F32(_) => CVType::from_primitive(PrimitiveType::Float32), + Expression::F64(_) => CVType::from_primitive(PrimitiveType::Float64), + Expression::String(_) => { + CVType::from_primitive(PrimitiveType::Pointer(Box::new(CVType { + type_: PrimitiveType::Int8, + const_: true, + volatile: false, + }))) + } + Expression::Cast(expr) => expr.type_.clone(), + Expression::Bracket(expr) => match expr.src.cv_type()?.type_ { + PrimitiveType::Pointer(t) => *t, + PrimitiveType::Array(t) => *t.cv_type, + _ => return Err(CompileError::BracketOnNonArrayOrPointer), + }, + Expression::Conditional(expr) => { + let cond_type = expr.cond.cv_type()?.type_; + if cond_type.is_bool_castable() { + let then_type = expr.then_expr.cv_type()?.type_; + let else_type = expr.else_expr.cv_type()?.type_; + match then_type.common_type(&else_type) { + Some(t) => CVType::from_primitive(t), + None => return Err(CompileError::ConditionalTypeMismatch), + } + } else { + return Err(CompileError::ConditionalNotBool); + } + } + Expression::InitializerList(expr) => unimplemented!("expression_type InitializerList"), + Expression::Paren(expr) => match expr.src.cv_type()?.type_ { + // @TODO arg check + PrimitiveType::Function(func) => *func.return_type, + _ => return Err(CompileError::CallNonFunction), + }, + Expression::Binary(expr) => unimplemented!("expression_type Binary"), + Expression::Unary(expr) => unimplemented!("expression_type Unary"), + Expression::Member(expr) => expr.member_type.clone(), + Expression::Arrow(expr) => expr.member_type.clone(), + }) + } +} #[derive(Debug, Clone)] pub struct ExprConditional { diff --git a/src/ast2/mod.rs b/src/ast2/mod.rs index 45e4165..1195c4c 100644 --- a/src/ast2/mod.rs +++ b/src/ast2/mod.rs @@ -54,3 +54,5 @@ pub use typename::PrimitiveType; pub use typename::StorageQualifier; pub use typename::StructMember; pub use typename::StructType; + +pub use context::Context; diff --git a/src/ast2/typename.rs b/src/ast2/typename.rs index dde3228..db2fdd1 100644 --- a/src/ast2/typename.rs +++ b/src/ast2/typename.rs @@ -1,3 +1,5 @@ +use super::CompileError; + #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub enum PrimitiveType { Void, @@ -52,6 +54,15 @@ impl PrimitiveType { pub fn is_float(&self) -> bool { matches!(self, PrimitiveType::Float32 | PrimitiveType::Float64) } + pub fn is_struct(&self) -> bool { + matches!(self, PrimitiveType::Struct(_)) + } + pub fn is_union(&self) -> bool { + matches!(self, PrimitiveType::Union(_)) + } + pub fn is_enum(&self) -> bool { + matches!(self, PrimitiveType::Enum(_)) + } pub fn is_bool_castable(&self) -> bool { match self { @@ -82,6 +93,41 @@ impl PrimitiveType { // } // None } + + pub fn sizeof(&self) -> Result { + Ok(match self { + PrimitiveType::Void => return Err(CompileError::SizeofIncompleteType), + PrimitiveType::UInt8 | PrimitiveType::Int8 => 1, + PrimitiveType::UInt16 | PrimitiveType::Int16 => 2, + PrimitiveType::UInt32 | PrimitiveType::Int32 | PrimitiveType::Float32 => 4, + PrimitiveType::UInt64 | PrimitiveType::Int64 | PrimitiveType::Float64 => 8, + PrimitiveType::Pointer(_) => 8, + PrimitiveType::Array(ArrayType { cv_type, size }) => cv_type.type_.sizeof()? * (*size), + PrimitiveType::Function(_) => return Err(CompileError::SizeofIncompleteType), + PrimitiveType::Struct(s) | PrimitiveType::Union(s) => match &s.body { + Some(s) => s.size, + None => return Err(CompileError::SizeofIncompleteType), + }, + PrimitiveType::Enum(e) => e.type_.sizeof()?, + }) + } + pub fn alignof(&self) -> Result { + Ok(match self { + PrimitiveType::Void => return Err(CompileError::SizeofIncompleteType), + PrimitiveType::UInt8 | PrimitiveType::Int8 => 1, + PrimitiveType::UInt16 | PrimitiveType::Int16 => 2, + PrimitiveType::UInt32 | PrimitiveType::Int32 | PrimitiveType::Float32 => 4, + PrimitiveType::UInt64 | PrimitiveType::Int64 | PrimitiveType::Float64 => 8, + PrimitiveType::Pointer(_) => 8, + PrimitiveType::Array(ArrayType { cv_type, size: _ }) => cv_type.type_.alignof()?, + PrimitiveType::Function(_) => return Err(CompileError::SizeofIncompleteType), + PrimitiveType::Struct(s) | PrimitiveType::Union(s) => match &s.body { + Some(s) => s.align, + None => return Err(CompileError::AlignofIncompleteType), + }, + PrimitiveType::Enum(e) => e.type_.alignof()?, + }) + } } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] @@ -115,6 +161,65 @@ pub struct StructMember { pub offset: usize, } +impl StructType { + pub fn struct_from_decls(name: Option, decls: Vec<(String, CVType)>) -> Self { + let mut size = 0; + let mut align = 1; + let mut members = Vec::new(); + for (name, member) in decls.into_iter() { + let member_size = member.type_.sizeof().unwrap(); + let member_align = member.type_.alignof().unwrap(); + let offset = ((size + member_align - 1) / member_align) * member_align; + align = std::cmp::max(align, member_align); + size = offset + member_size; + + members.push(StructMember { + name, + cv_type: member, + offset, + }); + } + let body = StructBody { + size, + align, + members, + }; + + StructType { + name, + body: Some(body), + } + } + pub fn union_from_decls(name: Option, decls: Vec<(String, CVType)>) -> Self { + let mut size = 0; + let mut align = 1; + let mut members = Vec::new(); + for (name, member) in decls.into_iter() { + let member_size = member.type_.sizeof().unwrap(); + let member_align = member.type_.alignof().unwrap(); + let offset = 0; + align = std::cmp::max(align, member_align); + size = std::cmp::max(size, member_size); + + members.push(StructMember { + name, + cv_type: member, + offset, + }); + } + let body = StructBody { + size, + align, + members, + }; + + StructType { + name, + body: Some(body), + } + } +} + #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct EnumType { pub name: Option, @@ -131,6 +236,25 @@ pub struct EnumMember { pub name: String, pub value: i64, } +impl EnumType { + pub fn enum_from_decls(name: Option, decls: Vec<(String, Option)>) -> Self { + let mut last_value = 0; + let mut members = Vec::new(); + for (name, value) in decls.into_iter() { + let value = match value { + Some(value) => value, + None => last_value + 1, + }; + last_value = value; + members.push(EnumMember { name, value }); + } + EnumType { + name, + body: Some(EnumBody { members }), + type_: Box::new(PrimitiveType::Int64), + } + } +} #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct CVType { diff --git a/src/ast2/variable.rs b/src/ast2/variable.rs index e956a27..da62324 100644 --- a/src/ast2/variable.rs +++ b/src/ast2/variable.rs @@ -46,3 +46,41 @@ pub enum Address { /// index on function array Function(usize), } + +impl Address { + pub fn is_global(&self) -> bool { + matches!(self, Address::Global(_)) + } + pub fn is_local(&self) -> bool { + matches!(self, Address::Local(_)) + } + pub fn is_function(&self) -> bool { + matches!(self, Address::Function(_)) + } + + pub fn into_u64(self) -> u64 { + match self { + Address::Global(x) => (x as u64) | (1u64 << 63), + Address::Local(x) => (x as u64) | (1u64 << 62), + Address::Function(x) => (x as u64) | (3u64 << 62), + } + } + pub fn from_u64(x: u64) -> Self { + match x >> 62 { + 1 => Address::Global((x & !(1u64 << 63)) as usize), + 2 => Address::Local((x & !(1u64 << 62)) as usize), + 3 => Address::Function((x & !(3u64 << 62)) as usize), + _ => unreachable!("invalid address"), + } + } +} +impl Into for Address { + fn into(self) -> u64 { + self.into_u64() + } +} +impl From for Address { + fn from(x: u64) -> Self { + Address::from_u64(x) + } +} diff --git a/src/main.rs b/src/main.rs index 4d7505b..8471bc8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,7 @@ mod ast; mod ast2; mod preprocess; mod token; -mod virtualmachine; +// mod virtualmachine; fn main() { println!("Enter your code (and ^D for EOF):"); @@ -86,10 +86,18 @@ fn main() { } } let translation_unit = context.accept(); + + let mut context = ast2::Context::new(); + let translation_unit = match context.process_translation_unit(translation_unit) { + Ok(tu) => tu, + Err(err) => { + println!("Error: {:?}", err); + return; + } + }; println!("{:#?}", translation_unit); /* - println!("{:#?}", translation_unit); // generate instructions println!("{:=^80}", ""); diff --git a/src/virtualmachine/generator.rs b/src/virtualmachine/generator.rs index f43ecc2..ea7fe23 100644 --- a/src/virtualmachine/generator.rs +++ b/src/virtualmachine/generator.rs @@ -3,6 +3,7 @@ use super::LabelType; use super::VirtualMachine; use crate::ast2; +use ast2::Address; use ast2::CompileError; use ast2::Expression; use ast2::Statement; @@ -48,12 +49,12 @@ impl InstructionGenerator { self.labels[label] = Some(addr); } - pub fn process( + pub fn emit( &mut self, translation_unit: ast2::TranslationUnit, ) -> Result { for statement in translation_unit.statements { - self.process_statement(statement)?; + self.emit_statement(statement)?; } let mut vm = VirtualMachine::new(); @@ -65,96 +66,168 @@ impl InstructionGenerator { Ok(vm) } - pub fn process_statement(&mut self, statement: Statement) -> Result<(), CompileError> { + pub fn emit_statement(&mut self, statement: Statement) -> Result<(), CompileError> { match statement { Statement::None => {} - Statement::Expression(stmt) => self.process_statement_expression(stmt), - Statement::Labeled(stmt) => self.process_statement_labeled(stmt), - Statement::Goto(stmt) => self.process_statement_goto(stmt), - Statement::Compound(stmt) => self.process_statement_compound(stmt), - Statement::If(stmt) => self.process_statement_if(stmt), - Statement::Switch(stmt) => self.process_statement_switch(stmt), + Statement::Expression(stmt) => self.emit_statement_expression(stmt), + Statement::Labeled(stmt) => self.emit_statement_labeled(stmt), + Statement::Goto(stmt) => self.emit_statement_goto(stmt), + Statement::Compound(stmt) => self.emit_statement_compound(stmt), + Statement::If(stmt) => self.emit_statement_if(stmt), + Statement::Switch(stmt) => self.emit_statement_switch(stmt), Statement::_Case(_) => unreachable!("_Case should not be visible to end-users"), Statement::_Default(_) => { unreachable!("_Default should not be visible to end-users") } - Statement::Continue => self.process_statement_continue(), - Statement::Break => self.process_statement_break(), - Statement::Return(stmt) => self.process_statement_return(stmt), - Statement::For(stmt) => self.process_statement_for(stmt), - Statement::While(stmt) => self.process_statement_while(stmt), - Statement::DoWhile(stmt) => self.process_statement_dowhile(stmt), - Statement::VariableDeclaration(stmt) => { - self.process_statement_variable_declaration(stmt) - } + Statement::Continue => self.emit_statement_continue(), + Statement::Break => self.emit_statement_break(), + Statement::Return(stmt) => self.emit_statement_return(stmt), + Statement::For(stmt) => self.emit_statement_for(stmt), + Statement::While(stmt) => self.emit_statement_while(stmt), + Statement::DoWhile(stmt) => self.emit_statement_dowhile(stmt), + Statement::VariableDeclaration(stmt) => self.emit_statement_variable_declaration(stmt), } Ok(()) } - pub fn process_expression(&mut self, expression: Expression) -> Result<(), CompileError> { + pub fn emit_expression(&mut self, expression: Expression) -> Result<(), CompileError> { match expression { - Expression::I8(expr) => self.process_expression_i8(expr), - Expression::I16(expr) => self.process_expression_i16(expr), - Expression::I32(expr) => self.process_expression_i32(expr), - Expression::I64(expr) => self.process_expression_i64(expr), - Expression::U8(expr) => self.process_expression_u8(expr), - Expression::U16(expr) => self.process_expression_u16(expr), - Expression::U32(expr) => self.process_expression_u32(expr), - Expression::U64(expr) => self.process_expression_u64(expr), - Expression::F32(expr) => self.process_expression_f32(expr), - Expression::F64(expr) => self.process_expression_f64(expr), - Expression::String(expr) => self.process_expression_string(expr), - Expression::Variable(expr) => self.process_expression_variable(expr), - Expression::Conditional(expr) => self.process_expression_conditional(expr), - Expression::Cast(expr) => self.process_expression_cast(expr), - Expression::Member(expr) => self.process_expression_member(expr), - Expression::Arrow(expr) => self.process_expression_arrow(expr), - Expression::Paren(expr) => self.process_expression_paren(expr), - Expression::Bracket(expr) => self.process_expression_bracket(expr), - Expression::Unary(expr) => self.process_expression_unary(expr), - Expression::Binary(expr) => self.process_expression_binary(expr), - Expression::InitializerList(expr) => self.process_expression_initializerlist(expr), + Expression::I8(expr) => self.emit_expression_i8(expr), + Expression::I16(expr) => self.emit_expression_i16(expr), + Expression::I32(expr) => self.emit_expression_i32(expr), + Expression::I64(expr) => self.emit_expression_i64(expr), + Expression::U8(expr) => self.emit_expression_u8(expr), + Expression::U16(expr) => self.emit_expression_u16(expr), + Expression::U32(expr) => self.emit_expression_u32(expr), + Expression::U64(expr) => self.emit_expression_u64(expr), + Expression::F32(expr) => self.emit_expression_f32(expr), + Expression::F64(expr) => self.emit_expression_f64(expr), + Expression::String(expr) => self.emit_expression_string(expr), + Expression::Variable(expr) => self.emit_expression_variable(expr), + Expression::Conditional(expr) => self.emit_expression_conditional(expr), + Expression::Cast(expr) => self.emit_expression_cast(expr), + Expression::Member(expr) => self.emit_expression_member(expr), + Expression::Arrow(expr) => self.emit_expression_arrow(expr), + Expression::Paren(expr) => self.emit_expression_paren(expr), + Expression::Bracket(expr) => self.emit_expression_bracket(expr), + Expression::Unary(expr) => self.emit_expression_unary(expr), + Expression::Binary(expr) => self.emit_expression_binary(expr), + Expression::InitializerList(expr) => self.emit_expression_initializerlist(expr), } Ok(()) } } impl InstructionGenerator { - fn process_statement_expression(&mut self, stmt: ast2::StmtExpression) {} - fn process_statement_labeled(&mut self, stmt: ast2::StmtLabeled) {} - fn process_statement_goto(&mut self, stmt: ast2::StmtGoto) {} - fn process_statement_compound(&mut self, stmt: ast2::StmtCompound) {} - fn process_statement_if(&mut self, stmt: ast2::StmtIf) {} - fn process_statement_switch(&mut self, stmt: ast2::StmtSwitch) {} - fn process_statement_continue(&mut self) {} - fn process_statement_break(&mut self) {} - fn process_statement_return(&mut self, stmt: ast2::StmtReturn) {} - fn process_statement_for(&mut self, stmt: ast2::StmtFor) {} - fn process_statement_while(&mut self, stmt: ast2::StmtWhile) {} - fn process_statement_dowhile(&mut self, stmt: ast2::StmtDoWhile) {} - fn process_statement_variable_declaration(&mut self, stmt: ast2::StmtVariableDeclaration) {} + fn emit_statement_expression(&mut self, stmt: ast2::StmtExpression) {} + fn emit_statement_labeled(&mut self, stmt: ast2::StmtLabeled) {} + fn emit_statement_goto(&mut self, stmt: ast2::StmtGoto) {} + fn emit_statement_compound(&mut self, stmt: ast2::StmtCompound) {} + fn emit_statement_if(&mut self, stmt: ast2::StmtIf) {} + fn emit_statement_switch(&mut self, stmt: ast2::StmtSwitch) {} + fn emit_statement_continue(&mut self) {} + fn emit_statement_break(&mut self) {} + fn emit_statement_return(&mut self, stmt: ast2::StmtReturn) {} + fn emit_statement_for(&mut self, stmt: ast2::StmtFor) {} + fn emit_statement_while(&mut self, stmt: ast2::StmtWhile) {} + fn emit_statement_dowhile(&mut self, stmt: ast2::StmtDoWhile) {} + fn emit_statement_variable_declaration(&mut self, stmt: ast2::StmtVariableDeclaration) {} } impl InstructionGenerator { - fn process_expression_i8(&mut self, expr: i8) {} - fn process_expression_i16(&mut self, expr: i16) {} - fn process_expression_i32(&mut self, expr: i32) {} - fn process_expression_i64(&mut self, expr: i64) {} - fn process_expression_u8(&mut self, expr: u8) {} - fn process_expression_u16(&mut self, expr: u16) {} - fn process_expression_u32(&mut self, expr: u32) {} - fn process_expression_u64(&mut self, expr: u64) {} - fn process_expression_f32(&mut self, expr: f32) {} - fn process_expression_f64(&mut self, expr: f64) {} - fn process_expression_string(&mut self, expr: String) {} - fn process_expression_variable(&mut self, expr: VariableInfo) {} - fn process_expression_conditional(&mut self, expr: ast2::ExprConditional) {} - fn process_expression_cast(&mut self, expr: ast2::ExprCast) {} - fn process_expression_member(&mut self, expr: ast2::ExprMember) {} - fn process_expression_arrow(&mut self, expr: ast2::ExprMember) {} - fn process_expression_paren(&mut self, expr: ast2::ExprParen) {} - fn process_expression_bracket(&mut self, expr: ast2::ExprBracket) {} - fn process_expression_unary(&mut self, expr: ast2::ExprUnary) {} - fn process_expression_binary(&mut self, expr: ast2::ExprBinary) {} - fn process_expression_initializerlist(&mut self, expr: ast2::ExprInitializerList) {} + fn emit_expression_i8(&mut self, expr: i8) { + self.instructions.push(Instruction::I64(expr as i64)); + } + fn emit_expression_i16(&mut self, expr: i16) { + self.instructions.push(Instruction::I64(expr as i64)); + } + fn emit_expression_i32(&mut self, expr: i32) { + self.instructions.push(Instruction::I64(expr as i64)); + } + fn emit_expression_i64(&mut self, expr: i64) { + self.instructions.push(Instruction::I64(expr)); + } + fn emit_expression_u8(&mut self, expr: u8) { + self.instructions.push(Instruction::U64(expr as u64)); + } + fn emit_expression_u16(&mut self, expr: u16) { + self.instructions.push(Instruction::U64(expr as u64)); + } + fn emit_expression_u32(&mut self, expr: u32) { + self.instructions.push(Instruction::U64(expr as u64)); + } + fn emit_expression_u64(&mut self, expr: u64) { + self.instructions.push(Instruction::U64(expr)); + } + fn emit_expression_f32(&mut self, expr: f32) { + let bits = expr.to_bits(); + self.instructions.push(Instruction::U64(bits as u64)); + } + fn emit_expression_f64(&mut self, expr: f64) { + let bits = expr.to_bits(); + self.instructions.push(Instruction::U64(bits)); + } + fn emit_expression_string(&mut self, expr: String) { + unimplemented!("emit_expression_string"); + } + fn emit_expression_variable(&mut self, expr: VariableInfo) { + self.instructions + .push(Instruction::U64(expr.address.into_u64())); + } + fn emit_expression_conditional(&mut self, expr: ast2::ExprConditional) { + let else_label = self.generate_label(); + let end_label = self.generate_label(); + + if self.cond.is_return_reference(instructions) { + self.emit_expression(*expr.cond); + + instructions.push(Instruction::JumpZero(JumpZero { + label: else_label.clone(), + operand_cond: Operand::Derefed(0, 0), + })); + } else { + self.emit_expression(*expr.cond); + + instructions.push(Instruction::JumpZero(JumpZero { + label: else_label.clone(), + operand_cond: Operand::Register(0), + })); + } + + self.then_expr.emit(instructions); + if self.then_expr.is_return_reference(instructions) { + instructions.push(Instruction::MoveRegister(MoveRegister { + operand_from: Operand::Derefed(0, 0), + operand_to: Operand::Register(1), + })); + instructions.push(Instruction::MoveRegister(MoveRegister { + operand_from: Operand::Register(1), + operand_to: Operand::Register(0), + })); + } + instructions.push(Instruction::Jump(Jump { + label: end_label.clone(), + })); + instructions.set_label(&else_label); + self.else_expr.emit(instructions); + if self.else_expr.is_return_reference(instructions) { + instructions.push(Instruction::MoveRegister(MoveRegister { + operand_from: Operand::Derefed(0, 0), + operand_to: Operand::Register(1), + })); + instructions.push(Instruction::MoveRegister(MoveRegister { + operand_from: Operand::Register(1), + operand_to: Operand::Register(0), + })); + } + instructions.set_label(&end_label); + } + fn emit_expression_cast(&mut self, expr: ast2::ExprCast) {} + fn emit_expression_member(&mut self, expr: ast2::ExprMember) {} + fn emit_expression_arrow(&mut self, expr: ast2::ExprMember) {} + fn emit_expression_paren(&mut self, expr: ast2::ExprParen) {} + fn emit_expression_bracket(&mut self, expr: ast2::ExprBracket) {} + fn emit_expression_unary(&mut self, expr: ast2::ExprUnary) {} + fn emit_expression_binary(&mut self, expr: ast2::ExprBinary) {} + fn emit_expression_initializerlist(&mut self, expr: ast2::ExprInitializerList) {} } diff --git a/src/virtualmachine/instruction.rs b/src/virtualmachine/instruction.rs index b26009d..704a8f9 100644 --- a/src/virtualmachine/instruction.rs +++ b/src/virtualmachine/instruction.rs @@ -1,7 +1,10 @@ -use super::program::{STACK_POINTER_BASE_REGISTER, STACK_POINTER_REGISTER, STACK_SIZE}; +use super::vm::{STACK_POINTER_BASE_REGISTER, STACK_POINTER_REGISTER, STACK_SIZE}; #[derive(Debug, Clone)] pub enum Instruction { + I64(i64), + U64(u64), + MoveRegister(MoveRegister), PushStack(PushStack), PopStack(PopStack), @@ -37,7 +40,6 @@ pub enum Instruction { impl Instruction { pub fn execute(&self, program: &mut VirtualMachine) { match self { - Instruction::DefineLabel(inst) => inst.execute(program), Instruction::MoveRegister(inst) => inst.execute(program), Instruction::PushStack(inst) => inst.execute(program), Instruction::PopStack(inst) => inst.execute(program), @@ -71,17 +73,6 @@ impl Instruction { } } -/// Do Nothing; for debugging -#[derive(Debug, Clone)] -pub struct DefineLabel { - pub label: String, -} -impl DefineLabel { - fn execute(&self, _program: &mut VirtualMachine) { - // label is defined at emitting session - } -} - /// copy register N to register M #[derive(Debug, Clone)] pub struct MoveRegister { @@ -156,7 +147,7 @@ pub struct Jump { pub label: String, } impl Jump { - fn execute(&self, program: &mut crate::virtualmachine::program::VirtualMachine) { + fn execute(&self, program: &mut crate::virtualmachine::vm::VirtualMachine) { let address = program .label_map .get(&self.label) @@ -173,7 +164,7 @@ pub struct JumpZero { pub operand_cond: Operand, } impl JumpZero { - fn execute(&self, program: &mut crate::virtualmachine::program::VirtualMachine) { + fn execute(&self, program: &mut crate::virtualmachine::vm::VirtualMachine) { let address = program .label_map .get(&self.label) @@ -193,7 +184,7 @@ pub struct JumpNonZero { pub operand_cond: Operand, } impl JumpNonZero { - fn execute(&self, program: &mut crate::virtualmachine::program::VirtualMachine) { + fn execute(&self, program: &mut crate::virtualmachine::vm::VirtualMachine) { let address = program .label_map .get(&self.label) @@ -210,7 +201,7 @@ impl JumpNonZero { #[derive(Debug, Clone)] pub struct Print {} impl Print { - fn execute(&self, program: &mut crate::virtualmachine::program::VirtualMachine) { + fn execute(&self, program: &mut crate::virtualmachine::vm::VirtualMachine) { PopStack { operand: Operand::Register(1), } @@ -236,7 +227,7 @@ pub struct Panic { pub message: String, } impl Panic { - fn execute(&self, _program: &mut crate::virtualmachine::program::VirtualMachine) { + fn execute(&self, _program: &mut crate::virtualmachine::vm::VirtualMachine) { panic!("Panic: {}", self.message); } } @@ -247,7 +238,7 @@ pub struct Call { pub label: String, } impl Call { - fn execute(&self, program: &mut crate::virtualmachine::program::VirtualMachine) { + fn execute(&self, program: &mut crate::virtualmachine::vm::VirtualMachine) { let move_to_address = *program .label_map .get(&self.label) @@ -269,7 +260,7 @@ impl Call { #[derive(Debug, Clone)] pub struct Return {} impl Return { - fn execute(&self, program: &mut crate::virtualmachine::program::VirtualMachine) { + fn execute(&self, program: &mut crate::virtualmachine::vm::VirtualMachine) { // register0 is beging used by returned value // current base pointer is old stack pointer @@ -291,7 +282,7 @@ pub struct PrintStr { pub str: Operand, // null terminated string } impl PrintStr { - fn execute(&self, program: &mut crate::virtualmachine::program::VirtualMachine) { + fn execute(&self, program: &mut crate::virtualmachine::vm::VirtualMachine) { let mut address = get_operand_value(program, &self.str).to_u64() as usize; let mut chars = Vec::new(); From 842c3e78de719e0dfa5332cb3b50278158750334 Mon Sep 17 00:00:00 2001 From: Taehwan Kim Date: Fri, 1 Nov 2024 00:02:26 +0900 Subject: [PATCH 08/10] fully implemented enhanced AST conversion --- src/ast/parser_lr.rs | 9 +- src/ast2/context.rs | 1089 +++++++++++++++++++++++++++++++++++++++- src/ast2/error.rs | 9 + src/ast2/expression.rs | 125 ++++- src/ast2/typename.rs | 245 ++++++++- 5 files changed, 1445 insertions(+), 32 deletions(-) diff --git a/src/ast/parser_lr.rs b/src/ast/parser_lr.rs index 6a8ec3f..d418725 100644 --- a/src/ast/parser_lr.rs +++ b/src/ast/parser_lr.rs @@ -700,6 +700,11 @@ selection_statement( Statement ) } ; +declaration_or_expression( Statement ) + : declaration + | expression_statement + ; + iteration_statement( Statement ) : while_ lparen expression rparen statement { @@ -714,7 +719,7 @@ iteration_statement( Statement ) statement: Box::new(statement), }) } - | for_ lparen init=expression_statement cond=expression_statement rparen body=statement { + | for_ lparen init=declaration_or_expression cond=expression_statement rparen body=statement { let Statement::Expression(cond) = cond else { unreachable!() }; Statement::For( statement::StmtFor{ init: Box::new(init), @@ -723,7 +728,7 @@ iteration_statement( Statement ) statement: Box::new(body), }) } - | for_ lparen init=expression_statement cond=expression_statement next=expression rparen body=statement { + | for_ lparen init=declaration_or_expression cond=expression_statement next=expression rparen body=statement { let Statement::Expression(cond) = cond else { unreachable!() }; Statement::For( statement::StmtFor{ init: Box::new(init), diff --git a/src/ast2/context.rs b/src/ast2/context.rs index 5711589..58c8723 100644 --- a/src/ast2/context.rs +++ b/src/ast2/context.rs @@ -11,6 +11,9 @@ use super::CVType; use super::CombinedDeclarator; use super::CompileError; use super::EnumType; +use super::ExprBinary; +use super::ExprBinaryOp; +use super::ExprUnaryOp; use super::Expression; use super::FunctionType; use super::PrimitiveType; @@ -656,9 +659,13 @@ impl Context { } } } - Ok(Statement::VariableDeclaration(StmtVariableDeclaration { - pairs, - })) + if pairs.is_empty() { + Ok(Statement::None) + } else { + Ok(Statement::VariableDeclaration(StmtVariableDeclaration { + pairs, + })) + } } None => { // struct, union, enum type definition @@ -1347,6 +1354,65 @@ impl Context { let cond = self.process_expression(*expr.cond)?; let then = self.process_expression(*expr.then_expr)?; let else_ = self.process_expression(*expr.else_expr)?; + match &cond { + Expression::U8(x) => { + if *x == 0 { + return Ok(else_); + } else { + return Ok(then); + } + } + Expression::U16(x) => { + if *x == 0 { + return Ok(else_); + } else { + return Ok(then); + } + } + Expression::U32(x) => { + if *x == 0 { + return Ok(else_); + } else { + return Ok(then); + } + } + Expression::U64(x) => { + if *x == 0 { + return Ok(else_); + } else { + return Ok(then); + } + } + Expression::I8(x) => { + if *x == 0 { + return Ok(else_); + } else { + return Ok(then); + } + } + Expression::I16(x) => { + if *x == 0 { + return Ok(else_); + } else { + return Ok(then); + } + } + Expression::I32(x) => { + if *x == 0 { + return Ok(else_); + } else { + return Ok(then); + } + } + Expression::I64(x) => { + if *x == 0 { + return Ok(else_); + } else { + return Ok(then); + } + } + _ => {} + } Ok(Expression::Conditional(expression::ExprConditional { cond: Box::new(cond), then_expr: Box::new(then), @@ -1358,6 +1424,154 @@ impl Context { expr: ast::ExprUnary, ) -> Result { let src = self.process_expression(*expr.src)?; + match expr.op { + ExprUnaryOp::AddressOf => { + if !src.is_address() { + return Err(CompileError::NotAssignable); + } + } + ExprUnaryOp::BitwiseNot => { + if !src.cv_type()?.type_.is_integer() { + return Err(CompileError::BitwiseOpOnNonInteger); + } + // compile-time constant + match src { + Expression::I8(x) => return Ok(Expression::U8(!x as u8)), + Expression::I16(x) => return Ok(Expression::U16(!x as u16)), + Expression::I32(x) => return Ok(Expression::U32(!x as u32)), + Expression::I64(x) => return Ok(Expression::U64(!x as u64)), + Expression::U8(x) => return Ok(Expression::U8(!x as u8)), + Expression::U16(x) => return Ok(Expression::U16(!x as u16)), + Expression::U32(x) => return Ok(Expression::U32(!x as u32)), + Expression::U64(x) => return Ok(Expression::U64(!x as u64)), + _ => {} + } + } + ExprUnaryOp::DecrementPost => { + if !src.cv_type()?.type_.is_integer() { + return Err(CompileError::BitwiseOpOnNonInteger); + } + if src.cv_type()?.const_ { + return Err(CompileError::AssignToConst); + } + if !src.is_address() { + return Err(CompileError::NotAssignable); + } + } + ExprUnaryOp::DecrementPre => { + if !src.cv_type()?.type_.is_integer() { + return Err(CompileError::BitwiseOpOnNonInteger); + } + if src.cv_type()?.const_ { + return Err(CompileError::AssignToConst); + } + if !src.is_address() { + return Err(CompileError::NotAssignable); + } + } + ExprUnaryOp::IncrementPost => { + if !src.cv_type()?.type_.is_integer() { + return Err(CompileError::BitwiseOpOnNonInteger); + } + if src.cv_type()?.const_ { + return Err(CompileError::AssignToConst); + } + if !src.is_address() { + return Err(CompileError::NotAssignable); + } + } + ExprUnaryOp::IncrementPre => { + if !src.cv_type()?.type_.is_integer() { + return Err(CompileError::BitwiseOpOnNonInteger); + } + if src.cv_type()?.const_ { + return Err(CompileError::AssignToConst); + } + if !src.is_address() { + return Err(CompileError::NotAssignable); + } + } + ExprUnaryOp::LogicalNot => { + if !src.cv_type()?.type_.is_bool_castable() { + return Err(CompileError::LogicalOpOnNonBool); + } + + // compile-time constant + match src { + Expression::I8(x) => return Ok(Expression::I32(if x == 0 { 1 } else { 0 })), + Expression::I16(x) => return Ok(Expression::I32(if x == 0 { 1 } else { 0 })), + Expression::I32(x) => return Ok(Expression::I32(if x == 0 { 1 } else { 0 })), + Expression::I64(x) => return Ok(Expression::I32(if x == 0 { 1 } else { 0 })), + Expression::U8(x) => return Ok(Expression::I32(if x == 0 { 1 } else { 0 })), + Expression::U16(x) => return Ok(Expression::I32(if x == 0 { 1 } else { 0 })), + Expression::U32(x) => return Ok(Expression::I32(if x == 0 { 1 } else { 0 })), + Expression::U64(x) => return Ok(Expression::I32(if x == 0 { 1 } else { 0 })), + _ => {} + } + } + ExprUnaryOp::Minus => { + match src.cv_type()?.type_ { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + match src { + Expression::I8(x) => return Ok(Expression::I8(-x)), + Expression::I16(x) => return Ok(Expression::I16(-x)), + Expression::I32(x) => return Ok(Expression::I32(-x)), + Expression::I64(x) => return Ok(Expression::I64(-x)), + Expression::U8(x) => return Ok(Expression::U8((-(x as i8)) as u8)), + Expression::U16(x) => return Ok(Expression::U16((-(x as i16)) as u16)), + Expression::U32(x) => return Ok(Expression::U32((-(x as i32)) as u32)), + Expression::U64(x) => return Ok(Expression::U64((-(x as i64)) as u64)), + _ => {} + } + } + ExprUnaryOp::Dereference => match src.cv_type()?.type_ { + PrimitiveType::Pointer(_) | PrimitiveType::Array(_) => {} + _ => { + return Err(CompileError::DereferenceOnNonPointer); + } + }, + ExprUnaryOp::Plus => { + match src.cv_type()?.type_ { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + match src { + Expression::I8(x) => return Ok(Expression::I8(x)), + Expression::I16(x) => return Ok(Expression::I16(x)), + Expression::I32(x) => return Ok(Expression::I32(x)), + Expression::I64(x) => return Ok(Expression::I64(x)), + Expression::U8(x) => return Ok(Expression::U8(x)), + Expression::U16(x) => return Ok(Expression::U16(x)), + Expression::U32(x) => return Ok(Expression::U32(x)), + Expression::U64(x) => return Ok(Expression::U64(x)), + _ => {} + } + } + } Ok(Expression::Unary(expression::ExprUnary { op: expr.op, expr: Box::new(src), @@ -1369,6 +1583,875 @@ impl Context { ) -> Result { let lhs = self.process_expression(*expr.lhs)?; let rhs = self.process_expression(*expr.rhs)?; + let lhs_type = lhs.cv_type()?.type_; + let rhs_type = rhs.cv_type()?.type_; + + match expr.op { + ExprBinaryOp::Add => { + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + } + + ExprBinaryOp::AddAssign => { + if !lhs.is_address() { + return Err(CompileError::NotAssignable); + } + if lhs.cv_type()?.const_ { + return Err(CompileError::AssignToConst); + } + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + } + ExprBinaryOp::Sub => { + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + } + ExprBinaryOp::SubAssign => { + if !lhs.is_address() { + return Err(CompileError::NotAssignable); + } + if lhs.cv_type()?.const_ { + return Err(CompileError::AssignToConst); + } + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + } + ExprBinaryOp::Mul => { + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + } + ExprBinaryOp::MulAssign => { + if !lhs.is_address() { + return Err(CompileError::NotAssignable); + } + if lhs.cv_type()?.const_ { + return Err(CompileError::AssignToConst); + } + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + } + ExprBinaryOp::Div => { + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + } + ExprBinaryOp::DivAssign => { + if !lhs.is_address() { + return Err(CompileError::NotAssignable); + } + if lhs.cv_type()?.const_ { + return Err(CompileError::AssignToConst); + } + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + } + ExprBinaryOp::Mod => { + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + } + ExprBinaryOp::ModAssign => { + if !lhs.is_address() { + return Err(CompileError::NotAssignable); + } + if lhs.cv_type()?.const_ { + return Err(CompileError::AssignToConst); + } + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + } + ExprBinaryOp::BitwiseAnd => { + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 => {} + _ => return Err(CompileError::BitwiseOpOnNonInteger), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 => {} + _ => return Err(CompileError::BitwiseOpOnNonInteger), + } + } + ExprBinaryOp::BitwiseAndAssign => { + if !lhs.is_address() { + return Err(CompileError::NotAssignable); + } + if lhs.cv_type()?.const_ { + return Err(CompileError::AssignToConst); + } + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 => {} + _ => return Err(CompileError::BitwiseOpOnNonInteger), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 => {} + _ => return Err(CompileError::BitwiseOpOnNonInteger), + } + } + ExprBinaryOp::BitwiseOr => { + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 => {} + _ => return Err(CompileError::BitwiseOpOnNonInteger), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 => {} + _ => return Err(CompileError::BitwiseOpOnNonInteger), + } + } + ExprBinaryOp::BitwiseOrAssign => { + if !lhs.is_address() { + return Err(CompileError::NotAssignable); + } + if lhs.cv_type()?.const_ { + return Err(CompileError::AssignToConst); + } + + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 => {} + _ => return Err(CompileError::BitwiseOpOnNonInteger), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 => {} + _ => return Err(CompileError::BitwiseOpOnNonInteger), + } + } + ExprBinaryOp::BitwiseXor => { + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 => {} + _ => return Err(CompileError::BitwiseOpOnNonInteger), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 => {} + _ => return Err(CompileError::BitwiseOpOnNonInteger), + } + } + ExprBinaryOp::BitwiseXorAssign => { + if !lhs.is_address() { + return Err(CompileError::NotAssignable); + } + if lhs.cv_type()?.const_ { + return Err(CompileError::AssignToConst); + } + + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 => {} + _ => return Err(CompileError::BitwiseOpOnNonInteger), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 => {} + _ => return Err(CompileError::BitwiseOpOnNonInteger), + } + } + ExprBinaryOp::ShiftLeft => { + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 => {} + _ => return Err(CompileError::BitwiseOpOnNonInteger), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 => {} + _ => return Err(CompileError::BitwiseOpOnNonInteger), + } + } + ExprBinaryOp::ShiftLeftAssign => { + if !lhs.is_address() { + return Err(CompileError::NotAssignable); + } + if lhs.cv_type()?.const_ { + return Err(CompileError::AssignToConst); + } + + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 => {} + _ => return Err(CompileError::BitwiseOpOnNonInteger), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 => {} + _ => return Err(CompileError::BitwiseOpOnNonInteger), + } + } + ExprBinaryOp::ShiftRight => { + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 => {} + _ => return Err(CompileError::BitwiseOpOnNonInteger), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 => {} + _ => return Err(CompileError::BitwiseOpOnNonInteger), + } + } + ExprBinaryOp::ShiftRightAssign => { + if !lhs.is_address() { + return Err(CompileError::NotAssignable); + } + if lhs.cv_type()?.const_ { + return Err(CompileError::AssignToConst); + } + + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 => {} + _ => return Err(CompileError::BitwiseOpOnNonInteger), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 => {} + _ => return Err(CompileError::BitwiseOpOnNonInteger), + } + } + ExprBinaryOp::Equal => { + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + } + ExprBinaryOp::NotEqual => { + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + } + ExprBinaryOp::LessThan => { + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + } + ExprBinaryOp::LessThanOrEqual => { + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + } + ExprBinaryOp::GreaterThan => { + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + } + ExprBinaryOp::GreaterThanOrEqual => { + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Float32 + | PrimitiveType::Float64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + } + } + ExprBinaryOp::LogicalAnd => { + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::LogicalOpOnNonBool), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::LogicalOpOnNonBool), + } + } + ExprBinaryOp::LogicalOr => { + match lhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::LogicalOpOnNonBool), + } + match rhs_type { + PrimitiveType::Int8 + | PrimitiveType::Int16 + | PrimitiveType::Int32 + | PrimitiveType::Int64 + | PrimitiveType::UInt8 + | PrimitiveType::UInt16 + | PrimitiveType::UInt32 + | PrimitiveType::UInt64 + | PrimitiveType::Pointer(_) + | PrimitiveType::Array(_) => {} + _ => return Err(CompileError::LogicalOpOnNonBool), + } + } + + ExprBinaryOp::Comma => {} + ExprBinaryOp::Assign => { + if !lhs.is_address() { + return Err(CompileError::NotAssignable); + } + if lhs.cv_type()?.const_ { + return Err(CompileError::AssignToConst); + } + match lhs_type { + PrimitiveType::Array(_) => return Err(CompileError::AssignToArray), + _ => {} + } + } + } + Ok(Expression::Binary(expression::ExprBinary { op: expr.op, lhs: Box::new(lhs), diff --git a/src/ast2/error.rs b/src/ast2/error.rs index da8f5d0..7e9b3b8 100644 --- a/src/ast2/error.rs +++ b/src/ast2/error.rs @@ -70,4 +70,13 @@ pub enum CompileError { ConditionalTypeMismatch, ConditionalNotBool, + + BitwiseOpOnNonInteger, + LogicalOpOnNonBool, + ArithmeticOpOnNonNumeric, + DereferenceOnNonPointer, + + NotAssignable, + AssignToArray, + AssignToConst, } diff --git a/src/ast2/expression.rs b/src/ast2/expression.rs index d327ee8..6839f0d 100644 --- a/src/ast2/expression.rs +++ b/src/ast2/expression.rs @@ -87,27 +87,118 @@ impl Expression { PrimitiveType::Array(t) => *t.cv_type, _ => return Err(CompileError::BracketOnNonArrayOrPointer), }, - Expression::Conditional(expr) => { - let cond_type = expr.cond.cv_type()?.type_; - if cond_type.is_bool_castable() { - let then_type = expr.then_expr.cv_type()?.type_; - let else_type = expr.else_expr.cv_type()?.type_; - match then_type.common_type(&else_type) { - Some(t) => CVType::from_primitive(t), - None => return Err(CompileError::ConditionalTypeMismatch), - } - } else { - return Err(CompileError::ConditionalNotBool); - } - } + Expression::Conditional(expr) => CVType::from_primitive( + expr.else_expr + .cv_type()? + .type_ + .common_type(&expr.then_expr.cv_type()?.type_) + .unwrap(), + ), Expression::InitializerList(expr) => unimplemented!("expression_type InitializerList"), Expression::Paren(expr) => match expr.src.cv_type()?.type_ { - // @TODO arg check PrimitiveType::Function(func) => *func.return_type, - _ => return Err(CompileError::CallNonFunction), + _ => unreachable!("Paren expression type"), + }, + Expression::Binary(expr) => match expr.op { + ExprBinaryOp::Add => CVType::from_primitive( + expr.lhs + .cv_type()? + .type_ + .common_type(&expr.rhs.cv_type()?.type_) + .unwrap(), + ), + ExprBinaryOp::AddAssign => expr.lhs.cv_type()?, + ExprBinaryOp::Sub => CVType::from_primitive( + expr.lhs + .cv_type()? + .type_ + .common_type(&expr.rhs.cv_type()?.type_) + .unwrap(), + ), + ExprBinaryOp::SubAssign => expr.lhs.cv_type()?, + ExprBinaryOp::Mul => CVType::from_primitive( + expr.lhs + .cv_type()? + .type_ + .common_type(&expr.rhs.cv_type()?.type_) + .unwrap(), + ), + ExprBinaryOp::MulAssign => expr.lhs.cv_type()?, + ExprBinaryOp::Div => CVType::from_primitive( + expr.lhs + .cv_type()? + .type_ + .common_type(&expr.rhs.cv_type()?.type_) + .unwrap(), + ), + ExprBinaryOp::DivAssign => expr.lhs.cv_type()?, + ExprBinaryOp::Mod => CVType::from_primitive( + expr.lhs + .cv_type()? + .type_ + .common_type(&expr.rhs.cv_type()?.type_) + .unwrap(), + ), + ExprBinaryOp::ModAssign => expr.lhs.cv_type()?, + ExprBinaryOp::BitwiseAnd => CVType::from_primitive( + expr.lhs + .cv_type()? + .type_ + .bit_common_type(&expr.rhs.cv_type()?.type_) + .unwrap(), + ), + ExprBinaryOp::BitwiseAndAssign => expr.lhs.cv_type()?, + ExprBinaryOp::BitwiseOr => CVType::from_primitive( + expr.lhs + .cv_type()? + .type_ + .bit_common_type(&expr.rhs.cv_type()?.type_) + .unwrap(), + ), + ExprBinaryOp::BitwiseOrAssign => expr.lhs.cv_type()?, + ExprBinaryOp::BitwiseXor => CVType::from_primitive( + expr.lhs + .cv_type()? + .type_ + .bit_common_type(&expr.rhs.cv_type()?.type_) + .unwrap(), + ), + ExprBinaryOp::BitwiseXorAssign => expr.lhs.cv_type()?, + ExprBinaryOp::ShiftLeft => CVType::from_primitive(expr.lhs.cv_type()?.type_), + ExprBinaryOp::ShiftLeftAssign => expr.lhs.cv_type()?, + ExprBinaryOp::ShiftRight => CVType::from_primitive(expr.lhs.cv_type()?.type_), + ExprBinaryOp::ShiftRightAssign => expr.lhs.cv_type()?, + ExprBinaryOp::Equal => CVType::from_primitive(PrimitiveType::Int32), + ExprBinaryOp::NotEqual => CVType::from_primitive(PrimitiveType::Int32), + ExprBinaryOp::LessThan => CVType::from_primitive(PrimitiveType::Int32), + ExprBinaryOp::LessThanOrEqual => CVType::from_primitive(PrimitiveType::Int32), + ExprBinaryOp::GreaterThan => CVType::from_primitive(PrimitiveType::Int32), + ExprBinaryOp::GreaterThanOrEqual => CVType::from_primitive(PrimitiveType::Int32), + ExprBinaryOp::LogicalAnd => CVType::from_primitive(PrimitiveType::Int32), + ExprBinaryOp::LogicalOr => CVType::from_primitive(PrimitiveType::Int32), + ExprBinaryOp::Comma => expr.rhs.cv_type()?, + ExprBinaryOp::Assign => expr.lhs.cv_type()?, + }, + Expression::Unary(expr) => match expr.op { + ExprUnaryOp::AddressOf => { + CVType::from_primitive(PrimitiveType::Pointer(Box::new(expr.expr.cv_type()?))) + } + ExprUnaryOp::BitwiseNot => { + CVType::from_primitive(expr.expr.cv_type()?.type_.to_unsigned().unwrap()) + } + ExprUnaryOp::DecrementPost => CVType::from_primitive(expr.expr.cv_type()?.type_), + ExprUnaryOp::DecrementPre => CVType::from_primitive(expr.expr.cv_type()?.type_), + ExprUnaryOp::IncrementPost => CVType::from_primitive(expr.expr.cv_type()?.type_), + ExprUnaryOp::IncrementPre => CVType::from_primitive(expr.expr.cv_type()?.type_), + ExprUnaryOp::LogicalNot => CVType::from_primitive(PrimitiveType::Int32), + ExprUnaryOp::Minus => CVType::from_primitive(expr.expr.cv_type()?.type_), + ExprUnaryOp::Dereference => match expr.expr.cv_type()?.type_ { + PrimitiveType::Pointer(t) => *t, + PrimitiveType::Array(t) => *t.cv_type, + _ => unreachable!("Dereference expression type"), + }, + ExprUnaryOp::Plus => CVType::from_primitive(expr.expr.cv_type()?.type_), }, - Expression::Binary(expr) => unimplemented!("expression_type Binary"), - Expression::Unary(expr) => unimplemented!("expression_type Unary"), Expression::Member(expr) => expr.member_type.clone(), Expression::Arrow(expr) => expr.member_type.clone(), }) diff --git a/src/ast2/typename.rs b/src/ast2/typename.rs index db2fdd1..9aa76cc 100644 --- a/src/ast2/typename.rs +++ b/src/ast2/typename.rs @@ -80,18 +80,230 @@ impl PrimitiveType { _ => false, } } + pub fn bit_common_type(&self, other: &Self) -> Option { + let lhs = match self { + PrimitiveType::UInt8 => 0, + PrimitiveType::UInt16 => 1, + PrimitiveType::UInt32 => 2, + PrimitiveType::UInt64 => 3, + PrimitiveType::Int8 => 0, + PrimitiveType::Int16 => 1, + PrimitiveType::Int32 => 2, + PrimitiveType::Int64 => 3, + _ => return None, + }; + let rhs = match other { + PrimitiveType::UInt8 => 0, + PrimitiveType::UInt16 => 1, + PrimitiveType::UInt32 => 2, + PrimitiveType::UInt64 => 3, + PrimitiveType::Int8 => 0, + PrimitiveType::Int16 => 1, + PrimitiveType::Int32 => 2, + PrimitiveType::Int64 => 3, + _ => return None, + }; + let common = lhs.max(rhs); + match common { + 0 => Some(PrimitiveType::UInt8), + 1 => Some(PrimitiveType::UInt16), + 2 => Some(PrimitiveType::UInt32), + 3 => Some(PrimitiveType::UInt64), + _ => unreachable!(), + } + } pub fn common_type(&self, other: &Self) -> Option { - unimplemented!("common_type") - // match (self, other) { - // (PrimitiveType::Void, _) | (_, PrimitiveType::Void) => None, - // (PrimitiveType::UInt8, PrimitiveType::UInt8) => Some(PrimitiveType::UInt8), - // (PrimitiveType::UInt16, PrimitiveType::UInt16) => Some(PrimitiveType::UInt16), - // (PrimitiveType::UInt32, PrimitiveType::UInt32) => Some(PrimitiveType::UInt32), - // (PrimitiveType::UInt64, PrimitiveType::UInt64) => Some(PrimitiveType::UInt64), - // (PrimitiveType::Int8, PrimitiveType::Int8) => Some(PrimitiveType::Int8), + match (self, other) { + (PrimitiveType::UInt8, PrimitiveType::UInt8) => Some(PrimitiveType::UInt8), + (PrimitiveType::UInt8, PrimitiveType::UInt16) => Some(PrimitiveType::UInt16), + (PrimitiveType::UInt8, PrimitiveType::UInt32) => Some(PrimitiveType::UInt32), + (PrimitiveType::UInt8, PrimitiveType::UInt64) => Some(PrimitiveType::UInt64), + (PrimitiveType::UInt8, PrimitiveType::Int8) => Some(PrimitiveType::UInt8), + (PrimitiveType::UInt8, PrimitiveType::Int16) => Some(PrimitiveType::UInt16), + (PrimitiveType::UInt8, PrimitiveType::Int32) => Some(PrimitiveType::UInt32), + (PrimitiveType::UInt8, PrimitiveType::Int64) => Some(PrimitiveType::UInt64), + (PrimitiveType::UInt8, PrimitiveType::Float32) => Some(PrimitiveType::Float32), + (PrimitiveType::UInt8, PrimitiveType::Float64) => Some(PrimitiveType::Float64), + (PrimitiveType::UInt8, PrimitiveType::Array(t)) => Some(t.cv_type.type_.clone()), + (PrimitiveType::UInt8, PrimitiveType::Pointer(t)) => Some(t.as_ref().type_.clone()), + (PrimitiveType::UInt8, _) => None, + + (PrimitiveType::UInt16, PrimitiveType::UInt8) => Some(PrimitiveType::UInt16), + (PrimitiveType::UInt16, PrimitiveType::UInt16) => Some(PrimitiveType::UInt16), + (PrimitiveType::UInt16, PrimitiveType::UInt32) => Some(PrimitiveType::UInt32), + (PrimitiveType::UInt16, PrimitiveType::UInt64) => Some(PrimitiveType::UInt64), + (PrimitiveType::UInt16, PrimitiveType::Int8) => Some(PrimitiveType::UInt16), + (PrimitiveType::UInt16, PrimitiveType::Int16) => Some(PrimitiveType::UInt16), + (PrimitiveType::UInt16, PrimitiveType::Int32) => Some(PrimitiveType::UInt32), + (PrimitiveType::UInt16, PrimitiveType::Int64) => Some(PrimitiveType::UInt64), + (PrimitiveType::UInt16, PrimitiveType::Float32) => Some(PrimitiveType::Float32), + (PrimitiveType::UInt16, PrimitiveType::Float64) => Some(PrimitiveType::Float64), + (PrimitiveType::UInt16, PrimitiveType::Array(t)) => Some(t.cv_type.type_.clone()), + (PrimitiveType::UInt16, PrimitiveType::Pointer(t)) => Some(t.as_ref().type_.clone()), + (PrimitiveType::UInt16, _) => None, + + (PrimitiveType::UInt32, PrimitiveType::UInt8) => Some(PrimitiveType::UInt32), + (PrimitiveType::UInt32, PrimitiveType::UInt16) => Some(PrimitiveType::UInt32), + (PrimitiveType::UInt32, PrimitiveType::UInt32) => Some(PrimitiveType::UInt32), + (PrimitiveType::UInt32, PrimitiveType::UInt64) => Some(PrimitiveType::UInt64), + (PrimitiveType::UInt32, PrimitiveType::Int8) => Some(PrimitiveType::UInt32), + (PrimitiveType::UInt32, PrimitiveType::Int16) => Some(PrimitiveType::UInt32), + (PrimitiveType::UInt32, PrimitiveType::Int32) => Some(PrimitiveType::UInt32), + (PrimitiveType::UInt32, PrimitiveType::Int64) => Some(PrimitiveType::UInt64), + (PrimitiveType::UInt32, PrimitiveType::Float32) => Some(PrimitiveType::Float32), + (PrimitiveType::UInt32, PrimitiveType::Float64) => Some(PrimitiveType::Float64), + (PrimitiveType::UInt32, PrimitiveType::Array(t)) => Some(t.cv_type.type_.clone()), + (PrimitiveType::UInt32, PrimitiveType::Pointer(t)) => Some(t.as_ref().type_.clone()), + (PrimitiveType::UInt32, _) => None, + + (PrimitiveType::UInt64, PrimitiveType::UInt8) => Some(PrimitiveType::UInt64), + (PrimitiveType::UInt64, PrimitiveType::UInt16) => Some(PrimitiveType::UInt64), + (PrimitiveType::UInt64, PrimitiveType::UInt32) => Some(PrimitiveType::UInt64), + (PrimitiveType::UInt64, PrimitiveType::UInt64) => Some(PrimitiveType::UInt64), + (PrimitiveType::UInt64, PrimitiveType::Int8) => Some(PrimitiveType::UInt64), + (PrimitiveType::UInt64, PrimitiveType::Int16) => Some(PrimitiveType::UInt64), + (PrimitiveType::UInt64, PrimitiveType::Int32) => Some(PrimitiveType::UInt64), + (PrimitiveType::UInt64, PrimitiveType::Int64) => Some(PrimitiveType::UInt64), + (PrimitiveType::UInt64, PrimitiveType::Float32) => Some(PrimitiveType::Float32), + (PrimitiveType::UInt64, PrimitiveType::Float64) => Some(PrimitiveType::Float64), + (PrimitiveType::UInt64, PrimitiveType::Array(t)) => Some(t.cv_type.type_.clone()), + (PrimitiveType::UInt64, PrimitiveType::Pointer(t)) => Some(t.as_ref().type_.clone()), + (PrimitiveType::UInt64, _) => None, + + (PrimitiveType::Int8, PrimitiveType::UInt8) => Some(PrimitiveType::UInt8), + (PrimitiveType::Int8, PrimitiveType::UInt16) => Some(PrimitiveType::UInt16), + (PrimitiveType::Int8, PrimitiveType::UInt32) => Some(PrimitiveType::UInt32), + (PrimitiveType::Int8, PrimitiveType::UInt64) => Some(PrimitiveType::UInt64), + (PrimitiveType::Int8, PrimitiveType::Int8) => Some(PrimitiveType::UInt8), + (PrimitiveType::Int8, PrimitiveType::Int16) => Some(PrimitiveType::UInt16), + (PrimitiveType::Int8, PrimitiveType::Int32) => Some(PrimitiveType::UInt32), + (PrimitiveType::Int8, PrimitiveType::Int64) => Some(PrimitiveType::UInt64), + (PrimitiveType::Int8, PrimitiveType::Float32) => Some(PrimitiveType::Float32), + (PrimitiveType::Int8, PrimitiveType::Float64) => Some(PrimitiveType::Float64), + (PrimitiveType::Int8, PrimitiveType::Array(t)) => Some(t.cv_type.type_.clone()), + (PrimitiveType::Int8, PrimitiveType::Pointer(t)) => Some(t.as_ref().type_.clone()), + (PrimitiveType::Int8, _) => None, + + (PrimitiveType::Int16, PrimitiveType::UInt8) => Some(PrimitiveType::UInt16), + (PrimitiveType::Int16, PrimitiveType::UInt16) => Some(PrimitiveType::UInt16), + (PrimitiveType::Int16, PrimitiveType::UInt32) => Some(PrimitiveType::UInt32), + (PrimitiveType::Int16, PrimitiveType::UInt64) => Some(PrimitiveType::UInt64), + (PrimitiveType::Int16, PrimitiveType::Int8) => Some(PrimitiveType::UInt16), + (PrimitiveType::Int16, PrimitiveType::Int16) => Some(PrimitiveType::UInt16), + (PrimitiveType::Int16, PrimitiveType::Int32) => Some(PrimitiveType::UInt32), + (PrimitiveType::Int16, PrimitiveType::Int64) => Some(PrimitiveType::UInt64), + (PrimitiveType::Int16, PrimitiveType::Float32) => Some(PrimitiveType::Float32), + (PrimitiveType::Int16, PrimitiveType::Float64) => Some(PrimitiveType::Float64), + (PrimitiveType::Int16, PrimitiveType::Array(t)) => Some(t.cv_type.type_.clone()), + (PrimitiveType::Int16, PrimitiveType::Pointer(t)) => Some(t.as_ref().type_.clone()), + (PrimitiveType::Int16, _) => None, + + (PrimitiveType::Int32, PrimitiveType::UInt8) => Some(PrimitiveType::UInt32), + (PrimitiveType::Int32, PrimitiveType::UInt16) => Some(PrimitiveType::UInt32), + (PrimitiveType::Int32, PrimitiveType::UInt32) => Some(PrimitiveType::UInt32), + (PrimitiveType::Int32, PrimitiveType::UInt64) => Some(PrimitiveType::UInt64), + (PrimitiveType::Int32, PrimitiveType::Int8) => Some(PrimitiveType::UInt32), + (PrimitiveType::Int32, PrimitiveType::Int16) => Some(PrimitiveType::UInt32), + (PrimitiveType::Int32, PrimitiveType::Int32) => Some(PrimitiveType::UInt32), + (PrimitiveType::Int32, PrimitiveType::Int64) => Some(PrimitiveType::UInt64), + (PrimitiveType::Int32, PrimitiveType::Float32) => Some(PrimitiveType::Float32), + (PrimitiveType::Int32, PrimitiveType::Float64) => Some(PrimitiveType::Float64), + (PrimitiveType::Int32, PrimitiveType::Array(t)) => Some(t.cv_type.type_.clone()), + (PrimitiveType::Int32, PrimitiveType::Pointer(t)) => Some(t.as_ref().type_.clone()), + (PrimitiveType::Int32, _) => None, - // } - // None + (PrimitiveType::Int64, PrimitiveType::UInt8) => Some(PrimitiveType::UInt64), + (PrimitiveType::Int64, PrimitiveType::UInt16) => Some(PrimitiveType::UInt64), + (PrimitiveType::Int64, PrimitiveType::UInt32) => Some(PrimitiveType::UInt64), + (PrimitiveType::Int64, PrimitiveType::UInt64) => Some(PrimitiveType::UInt64), + (PrimitiveType::Int64, PrimitiveType::Int8) => Some(PrimitiveType::UInt64), + (PrimitiveType::Int64, PrimitiveType::Int16) => Some(PrimitiveType::UInt64), + (PrimitiveType::Int64, PrimitiveType::Int32) => Some(PrimitiveType::UInt64), + (PrimitiveType::Int64, PrimitiveType::Int64) => Some(PrimitiveType::UInt64), + (PrimitiveType::Int64, PrimitiveType::Float32) => Some(PrimitiveType::Float32), + (PrimitiveType::Int64, PrimitiveType::Float64) => Some(PrimitiveType::Float64), + (PrimitiveType::Int64, PrimitiveType::Array(t)) => Some(t.cv_type.type_.clone()), + (PrimitiveType::Int64, PrimitiveType::Pointer(t)) => Some(t.as_ref().type_.clone()), + (PrimitiveType::Int64, _) => None, + + (PrimitiveType::Float32, PrimitiveType::UInt8) => Some(PrimitiveType::Float32), + (PrimitiveType::Float32, PrimitiveType::UInt16) => Some(PrimitiveType::Float32), + (PrimitiveType::Float32, PrimitiveType::UInt32) => Some(PrimitiveType::Float32), + (PrimitiveType::Float32, PrimitiveType::UInt64) => Some(PrimitiveType::Float32), + (PrimitiveType::Float32, PrimitiveType::Int8) => Some(PrimitiveType::Float32), + (PrimitiveType::Float32, PrimitiveType::Int16) => Some(PrimitiveType::Float32), + (PrimitiveType::Float32, PrimitiveType::Int32) => Some(PrimitiveType::Float32), + (PrimitiveType::Float32, PrimitiveType::Int64) => Some(PrimitiveType::Float32), + (PrimitiveType::Float32, PrimitiveType::Float32) => Some(PrimitiveType::Float32), + (PrimitiveType::Float32, PrimitiveType::Float64) => Some(PrimitiveType::Float64), + (PrimitiveType::Float32, _) => None, + + (PrimitiveType::Float64, PrimitiveType::UInt8) => Some(PrimitiveType::Float64), + (PrimitiveType::Float64, PrimitiveType::UInt16) => Some(PrimitiveType::Float64), + (PrimitiveType::Float64, PrimitiveType::UInt32) => Some(PrimitiveType::Float64), + (PrimitiveType::Float64, PrimitiveType::UInt64) => Some(PrimitiveType::Float64), + (PrimitiveType::Float64, PrimitiveType::Int8) => Some(PrimitiveType::Float64), + (PrimitiveType::Float64, PrimitiveType::Int16) => Some(PrimitiveType::Float64), + (PrimitiveType::Float64, PrimitiveType::Int32) => Some(PrimitiveType::Float64), + (PrimitiveType::Float64, PrimitiveType::Int64) => Some(PrimitiveType::Float64), + (PrimitiveType::Float64, PrimitiveType::Float32) => Some(PrimitiveType::Float64), + (PrimitiveType::Float64, PrimitiveType::Float64) => Some(PrimitiveType::Float64), + (PrimitiveType::Float64, _) => None, + + (PrimitiveType::Pointer(t), PrimitiveType::UInt8) => { + Some(PrimitiveType::Pointer(t.clone())) + } + (PrimitiveType::Pointer(t), PrimitiveType::UInt16) => { + Some(PrimitiveType::Pointer(t.clone())) + } + (PrimitiveType::Pointer(t), PrimitiveType::UInt32) => { + Some(PrimitiveType::Pointer(t.clone())) + } + (PrimitiveType::Pointer(t), PrimitiveType::UInt64) => { + Some(PrimitiveType::Pointer(t.clone())) + } + (PrimitiveType::Pointer(t), PrimitiveType::Int8) => { + Some(PrimitiveType::Pointer(t.clone())) + } + (PrimitiveType::Pointer(t), PrimitiveType::Int16) => { + Some(PrimitiveType::Pointer(t.clone())) + } + (PrimitiveType::Pointer(t), PrimitiveType::Int32) => { + Some(PrimitiveType::Pointer(t.clone())) + } + (PrimitiveType::Pointer(t), PrimitiveType::Int64) => { + Some(PrimitiveType::Pointer(t.clone())) + } + (PrimitiveType::Pointer(t), _) => None, + + (PrimitiveType::Array(t), PrimitiveType::UInt8) => { + Some(PrimitiveType::Pointer(t.cv_type.clone())) + } + (PrimitiveType::Array(t), PrimitiveType::UInt16) => { + Some(PrimitiveType::Pointer(t.cv_type.clone())) + } + (PrimitiveType::Array(t), PrimitiveType::UInt32) => { + Some(PrimitiveType::Pointer(t.cv_type.clone())) + } + (PrimitiveType::Array(t), PrimitiveType::UInt64) => { + Some(PrimitiveType::Pointer(t.cv_type.clone())) + } + (PrimitiveType::Array(t), PrimitiveType::Int8) => { + Some(PrimitiveType::Pointer(t.cv_type.clone())) + } + (PrimitiveType::Array(t), PrimitiveType::Int16) => { + Some(PrimitiveType::Pointer(t.cv_type.clone())) + } + (PrimitiveType::Array(t), PrimitiveType::Int32) => { + Some(PrimitiveType::Pointer(t.cv_type.clone())) + } + (PrimitiveType::Array(t), PrimitiveType::Int64) => { + Some(PrimitiveType::Pointer(t.cv_type.clone())) + } + (PrimitiveType::Array(t), _) => None, + + _ => None, + } } pub fn sizeof(&self) -> Result { @@ -128,6 +340,19 @@ impl PrimitiveType { PrimitiveType::Enum(e) => e.type_.alignof()?, }) } + pub fn to_unsigned(&self) -> Option { + match self { + PrimitiveType::Int8 => Some(PrimitiveType::UInt8), + PrimitiveType::Int16 => Some(PrimitiveType::UInt16), + PrimitiveType::Int32 => Some(PrimitiveType::UInt32), + PrimitiveType::Int64 => Some(PrimitiveType::UInt64), + PrimitiveType::UInt8 => Some(PrimitiveType::UInt8), + PrimitiveType::UInt16 => Some(PrimitiveType::UInt16), + PrimitiveType::UInt32 => Some(PrimitiveType::UInt32), + PrimitiveType::UInt64 => Some(PrimitiveType::UInt64), + _ => None, + } + } } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] From c7159ef9d0a7f047ac39953f64e37a7a9ee522e7 Mon Sep 17 00:00:00 2001 From: Taehwan Kim Date: Mon, 4 Nov 2024 20:53:00 +0900 Subject: [PATCH 09/10] split integer, float type into separated type group --- src/ast2/context.rs | 1401 +++++++++-------------------- src/ast2/declarator.rs | 22 +- src/ast2/error.rs | 15 + src/ast2/expression.rs | 353 +++++--- src/ast2/mod.rs | 2 + src/ast2/typename.rs | 480 ++++------ src/virtualmachine/generator.rs | 146 +-- src/virtualmachine/instruction.rs | 10 +- 8 files changed, 948 insertions(+), 1481 deletions(-) diff --git a/src/ast2/context.rs b/src/ast2/context.rs index 58c8723..b252466 100644 --- a/src/ast2/context.rs +++ b/src/ast2/context.rs @@ -15,7 +15,9 @@ use super::ExprBinary; use super::ExprBinaryOp; use super::ExprUnaryOp; use super::Expression; +use super::Float; use super::FunctionType; +use super::Integer; use super::PrimitiveType; use super::Statement; use super::StmtSwitchCase; @@ -1170,43 +1172,43 @@ impl Context { &mut self, expr: ast::ExprConstantCharacter, ) -> Result { - Ok(Expression::I8(expr.value)) + Ok(Expression::Signed(expr.value as i64, Integer::Int8)) } pub(crate) fn process_expression_constantinteger( &mut self, expr: ast::ExprConstantInteger, ) -> Result { - Ok(Expression::I32(expr.value)) + Ok(Expression::Signed(expr.value as i64, Integer::Int32)) } pub(crate) fn process_expression_constantunsignedinteger( &mut self, expr: ast::ExprConstantUnsignedInteger, ) -> Result { - Ok(Expression::U32(expr.value)) + Ok(Expression::Unsigned(expr.value as u64, Integer::UInt32)) } pub(crate) fn process_expression_constantlong( &mut self, expr: ast::ExprConstantLong, ) -> Result { - Ok(Expression::I64(expr.value)) + Ok(Expression::Signed(expr.value, Integer::Int64)) } pub(crate) fn process_expression_constantunsignedlong( &mut self, expr: ast::ExprConstantUnsignedLong, ) -> Result { - Ok(Expression::U64(expr.value)) + Ok(Expression::Unsigned(expr.value, Integer::UInt64)) } pub(crate) fn process_expression_constantfloat( &mut self, expr: ast::ExprConstantFloat, ) -> Result { - Ok(Expression::F32(expr.value)) + Ok(Expression::Float(expr.value as f64, Float::Float32)) } pub(crate) fn process_expression_constantdouble( &mut self, expr: ast::ExprConstantDouble, ) -> Result { - Ok(Expression::F64(expr.value)) + Ok(Expression::Float(expr.value, Float::Float64)) } pub(crate) fn process_expression_string( &mut self, @@ -1214,6 +1216,100 @@ impl Context { ) -> Result { Ok(Expression::String(expr.value)) } + pub(crate) fn process_expression_cast( + &mut self, + expr: ast::ExprCast, + ) -> Result { + let base_type = self.process_specs(expr.typename.specs.into_iter())?; + let type_to = if let Some(decl) = expr.typename.declarator { + let decl = self.process_declarator(*decl, base_type)?; + decl.cv_type.type_ + } else { + base_type.type_ + }; + let src = self.process_expression(*expr.src)?; + if !src.cv_type()?.type_.is_castable(&type_to) { + return Err(CompileError::InvalidCast(src.cv_type()?.type_, type_to)); + } else { + Ok(Expression::Cast(expression::ExprCast { + expr: Box::new(src), + type_: type_to, + })) + } + } + pub(crate) fn process_expression_bracket( + &mut self, + expr: ast::ExprBracket, + ) -> Result { + let src = self.process_expression(*expr.src)?; + match src.cv_type()?.type_ { + PrimitiveType::Array(_) | PrimitiveType::Pointer(_) => {} + _ => return Err(CompileError::BracketOnNonArrayOrPointer), + } + let index = self.process_expression(*expr.index)?; + if !matches!(index.cv_type()?.type_, PrimitiveType::Integer(_)) { + return Err(CompileError::BracketIndexNotInteger); + } + + Ok(Expression::Bracket(expression::ExprBracket { + src: Box::new(src), + index: Box::new(index), + })) + } + pub(crate) fn process_expression_conditional( + &mut self, + expr: ast::ExprConditional, + ) -> Result { + let cond = self.process_expression(*expr.cond)?; + let then = self.process_expression(*expr.then_expr)?; + let else_ = self.process_expression(*expr.else_expr)?; + if !cond.cv_type()?.type_.is_bool_castable() { + return Err(CompileError::ConditionalNotBool); + } + match &cond { + Expression::Signed(x, _) => { + if *x == 0 { + return Ok(else_); + } else { + return Ok(then); + } + } + Expression::Unsigned(x, _) => { + if *x == 0 { + return Ok(else_); + } else { + return Ok(then); + } + } + _ => {} + } + let then_type = then.cv_type()?.type_; + let else_type = else_.cv_type()?.type_; + let common_type = match then_type.common_type(&else_type) { + Some(common) => common, + None => return Err(CompileError::NoCommonType(then_type, else_type)), + }; + Ok(Expression::Conditional(expression::ExprConditional { + cond: Box::new(cond), + then_expr: if then_type != common_type { + Box::new(Expression::Cast(super::ExprCast { + expr: Box::new(then), + type_: common_type.clone(), + })) + } else { + Box::new(then) + }, + else_expr: if else_type != common_type { + Box::new(Expression::Cast(super::ExprCast { + expr: Box::new(else_), + type_: common_type, + })) + } else { + Box::new(else_) + }, + })) + } + pub(crate) fn process_expression_member( &mut self, expr: ast::ExprMember, @@ -1271,61 +1367,41 @@ impl Context { _ => return Err(CompileError::ArrowOnNonStructOrUnion), } } - pub(crate) fn process_expression_bracket( - &mut self, - expr: ast::ExprBracket, - ) -> Result { - let src = self.process_expression(*expr.src)?; - match src.cv_type()?.type_ { - PrimitiveType::Array(_) | PrimitiveType::Pointer(_) => {} - _ => return Err(CompileError::BracketOnNonArrayOrPointer), - } - let index = self.process_expression(*expr.index)?; - if !index.cv_type()?.type_.is_integer() { - return Err(CompileError::BracketIndexNotInteger); - } - - Ok(Expression::Bracket(expression::ExprBracket { - src: Box::new(src), - index: Box::new(index), - })) - } pub(crate) fn process_expression_paren( &mut self, expr: ast::ExprParen, ) -> Result { let src = self.process_expression(*expr.src)?; match src.cv_type()?.type_ { - PrimitiveType::Function(_func_info) => { - // @TODO argument type, variadic check + PrimitiveType::Function(func_info) => { + if expr.args.len() != func_info.args.len() { + if !func_info.variadic || !(expr.args.len() > func_info.args.len()) { + return Err(CompileError::CallWithWrongNumberOfArguments); + } + } + + let args = expr + .args + .into_iter() + .enumerate() + .map(|(idx, expr)| -> Result { + let arg_expr = self.process_expression(expr)?; + let arg_type = arg_expr.cv_type()?.type_; + + if !arg_type.is_implicitly_castable(&func_info.args[idx].type_) { + return Err(CompileError::CallWithWrongArgumentType); + } + Ok(arg_expr) + }) + .collect::, _>>()?; + + Ok(Expression::Paren(expression::ExprParen { + src: Box::new(src), + args, + })) } _ => return Err(CompileError::CallNonFunction), } - Ok(Expression::Paren(expression::ExprParen { - src: Box::new(src), - args: expr - .args - .into_iter() - .map(|expr| self.process_expression(expr)) - .collect::, _>>()?, - })) - } - pub(crate) fn process_expression_cast( - &mut self, - expr: ast::ExprCast, - ) -> Result { - let base_type = self.process_specs(expr.typename.specs.into_iter())?; - let type_to = if let Some(decl) = expr.typename.declarator { - let decl = self.process_declarator(*decl, base_type)?; - decl.cv_type - } else { - base_type - }; - // @TODO check castable - Ok(Expression::Cast(expression::ExprCast { - expr: Box::new(self.process_expression(*expr.src)?), - type_: type_to, - })) } pub(crate) fn process_expression_sizeoftype( &mut self, @@ -1337,7 +1413,10 @@ impl Context { } else { base_type }; - Ok(Expression::U64(typename.type_.sizeof()? as u64)) + Ok(Expression::Unsigned( + typename.type_.sizeof()? as u64, + Integer::UInt64, + )) } pub(crate) fn process_expression_sizeofexpr( &mut self, @@ -1345,85 +1424,17 @@ impl Context { ) -> Result { let expr = self.process_expression(*expr.expr)?; let typename = expr.cv_type()?; - Ok(Expression::U64(typename.type_.sizeof()? as u64)) - } - pub(crate) fn process_expression_conditional( - &mut self, - expr: ast::ExprConditional, - ) -> Result { - let cond = self.process_expression(*expr.cond)?; - let then = self.process_expression(*expr.then_expr)?; - let else_ = self.process_expression(*expr.else_expr)?; - match &cond { - Expression::U8(x) => { - if *x == 0 { - return Ok(else_); - } else { - return Ok(then); - } - } - Expression::U16(x) => { - if *x == 0 { - return Ok(else_); - } else { - return Ok(then); - } - } - Expression::U32(x) => { - if *x == 0 { - return Ok(else_); - } else { - return Ok(then); - } - } - Expression::U64(x) => { - if *x == 0 { - return Ok(else_); - } else { - return Ok(then); - } - } - Expression::I8(x) => { - if *x == 0 { - return Ok(else_); - } else { - return Ok(then); - } - } - Expression::I16(x) => { - if *x == 0 { - return Ok(else_); - } else { - return Ok(then); - } - } - Expression::I32(x) => { - if *x == 0 { - return Ok(else_); - } else { - return Ok(then); - } - } - Expression::I64(x) => { - if *x == 0 { - return Ok(else_); - } else { - return Ok(then); - } - } - _ => {} - } - Ok(Expression::Conditional(expression::ExprConditional { - cond: Box::new(cond), - then_expr: Box::new(then), - else_expr: Box::new(else_), - })) + Ok(Expression::Unsigned( + typename.type_.sizeof()? as u64, + Integer::UInt64, + )) } pub(crate) fn process_expression_unary( &mut self, expr: ast::ExprUnary, ) -> Result { let src = self.process_expression(*expr.src)?; + let src_type = src.cv_type()?; match expr.op { ExprUnaryOp::AddressOf => { if !src.is_address() { @@ -1431,27 +1442,25 @@ impl Context { } } ExprUnaryOp::BitwiseNot => { - if !src.cv_type()?.type_.is_integer() { + if !matches!(src_type.type_, PrimitiveType::Integer(_)) { return Err(CompileError::BitwiseOpOnNonInteger); } // compile-time constant match src { - Expression::I8(x) => return Ok(Expression::U8(!x as u8)), - Expression::I16(x) => return Ok(Expression::U16(!x as u16)), - Expression::I32(x) => return Ok(Expression::U32(!x as u32)), - Expression::I64(x) => return Ok(Expression::U64(!x as u64)), - Expression::U8(x) => return Ok(Expression::U8(!x as u8)), - Expression::U16(x) => return Ok(Expression::U16(!x as u16)), - Expression::U32(x) => return Ok(Expression::U32(!x as u32)), - Expression::U64(x) => return Ok(Expression::U64(!x as u64)), + Expression::Signed(x, type_) => { + return Ok(Expression::Unsigned((!x) as u64, type_.to_unsigned())); + } + Expression::Unsigned(x, type_) => { + return Ok(Expression::Unsigned(!x as u64, type_.to_unsigned())); + } _ => {} } } ExprUnaryOp::DecrementPost => { - if !src.cv_type()?.type_.is_integer() { + if !matches!(src_type.type_, PrimitiveType::Integer(_)) { return Err(CompileError::BitwiseOpOnNonInteger); } - if src.cv_type()?.const_ { + if src_type.const_ { return Err(CompileError::AssignToConst); } if !src.is_address() { @@ -1459,10 +1468,10 @@ impl Context { } } ExprUnaryOp::DecrementPre => { - if !src.cv_type()?.type_.is_integer() { + if !matches!(src_type.type_, PrimitiveType::Integer(_)) { return Err(CompileError::BitwiseOpOnNonInteger); } - if src.cv_type()?.const_ { + if src_type.const_ { return Err(CompileError::AssignToConst); } if !src.is_address() { @@ -1470,10 +1479,10 @@ impl Context { } } ExprUnaryOp::IncrementPost => { - if !src.cv_type()?.type_.is_integer() { + if !matches!(src_type.type_, PrimitiveType::Integer(_)) { return Err(CompileError::BitwiseOpOnNonInteger); } - if src.cv_type()?.const_ { + if src_type.const_ { return Err(CompileError::AssignToConst); } if !src.is_address() { @@ -1481,10 +1490,10 @@ impl Context { } } ExprUnaryOp::IncrementPre => { - if !src.cv_type()?.type_.is_integer() { + if !matches!(src_type.type_, PrimitiveType::Integer(_)) { return Err(CompileError::BitwiseOpOnNonInteger); } - if src.cv_type()?.const_ { + if src_type.const_ { return Err(CompileError::AssignToConst); } if !src.is_address() { @@ -1492,84 +1501,59 @@ impl Context { } } ExprUnaryOp::LogicalNot => { - if !src.cv_type()?.type_.is_bool_castable() { + if !src_type.type_.is_bool_castable() { return Err(CompileError::LogicalOpOnNonBool); } // compile-time constant match src { - Expression::I8(x) => return Ok(Expression::I32(if x == 0 { 1 } else { 0 })), - Expression::I16(x) => return Ok(Expression::I32(if x == 0 { 1 } else { 0 })), - Expression::I32(x) => return Ok(Expression::I32(if x == 0 { 1 } else { 0 })), - Expression::I64(x) => return Ok(Expression::I32(if x == 0 { 1 } else { 0 })), - Expression::U8(x) => return Ok(Expression::I32(if x == 0 { 1 } else { 0 })), - Expression::U16(x) => return Ok(Expression::I32(if x == 0 { 1 } else { 0 })), - Expression::U32(x) => return Ok(Expression::I32(if x == 0 { 1 } else { 0 })), - Expression::U64(x) => return Ok(Expression::I32(if x == 0 { 1 } else { 0 })), + Expression::Signed(x, _) => { + return Ok(Expression::Signed( + if x == 0 { 1 } else { 0 }, + Integer::Int32, + )) + } + Expression::Unsigned(x, _) => { + return Ok(Expression::Signed( + if x == 0 { 1 } else { 0 }, + Integer::Int32, + )) + } _ => {} } } ExprUnaryOp::Minus => { - match src.cv_type()?.type_ { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + if !matches!( + &src_type.type_, + PrimitiveType::Integer(_) | PrimitiveType::Float(_) + ) { + return Err(CompileError::ArithmeticOpOnNonNumeric); } match src { - Expression::I8(x) => return Ok(Expression::I8(-x)), - Expression::I16(x) => return Ok(Expression::I16(-x)), - Expression::I32(x) => return Ok(Expression::I32(-x)), - Expression::I64(x) => return Ok(Expression::I64(-x)), - Expression::U8(x) => return Ok(Expression::U8((-(x as i8)) as u8)), - Expression::U16(x) => return Ok(Expression::U16((-(x as i16)) as u16)), - Expression::U32(x) => return Ok(Expression::U32((-(x as i32)) as u32)), - Expression::U64(x) => return Ok(Expression::U64((-(x as i64)) as u64)), + Expression::Signed(x, type_) => return Ok(Expression::Signed(-x, type_)), + Expression::Unsigned(x, type_) => { + return Ok(Expression::Unsigned((-(x as i64)) as u64, type_)); + } + Expression::Float(x, type_) => return Ok(Expression::Float(-x, type_)), _ => {} } } - ExprUnaryOp::Dereference => match src.cv_type()?.type_ { - PrimitiveType::Pointer(_) | PrimitiveType::Array(_) => {} - _ => { + ExprUnaryOp::Dereference => { + if !matches!( + src_type.type_, + PrimitiveType::Pointer(_) | PrimitiveType::Array(_) + ) { return Err(CompileError::DereferenceOnNonPointer); } - }, + } ExprUnaryOp::Plus => { - match src.cv_type()?.type_ { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - match src { - Expression::I8(x) => return Ok(Expression::I8(x)), - Expression::I16(x) => return Ok(Expression::I16(x)), - Expression::I32(x) => return Ok(Expression::I32(x)), - Expression::I64(x) => return Ok(Expression::I64(x)), - Expression::U8(x) => return Ok(Expression::U8(x)), - Expression::U16(x) => return Ok(Expression::U16(x)), - Expression::U32(x) => return Ok(Expression::U32(x)), - Expression::U64(x) => return Ok(Expression::U64(x)), - _ => {} + if !matches!( + &src_type.type_, + PrimitiveType::Integer(_) | PrimitiveType::Float(_) + ) { + return Err(CompileError::ArithmeticOpOnNonNumeric); } + return Ok(src); } } Ok(Expression::Unary(expression::ExprUnary { @@ -1587,38 +1571,20 @@ impl Context { let rhs_type = rhs.cv_type()?.type_; match expr.op { - ExprBinaryOp::Add => { - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - } + ExprBinaryOp::Add => match (lhs_type, rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} + (PrimitiveType::Integer(_), PrimitiveType::Pointer(_)) => {} + (PrimitiveType::Integer(_), PrimitiveType::Array(_)) => {} + + (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + + (PrimitiveType::Pointer(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Array(_), PrimitiveType::Integer(_)) => {} + + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + }, ExprBinaryOp::AddAssign => { if !lhs.is_address() { @@ -1627,69 +1593,35 @@ impl Context { if lhs.cv_type()?.const_ { return Err(CompileError::AssignToConst); } - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - } - ExprBinaryOp::Sub => { - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} + match (lhs_type, rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} + (PrimitiveType::Integer(_), PrimitiveType::Pointer(_)) => {} + (PrimitiveType::Integer(_), PrimitiveType::Array(_)) => {} + + (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + + (PrimitiveType::Pointer(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Array(_), PrimitiveType::Integer(_)) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), } } + ExprBinaryOp::Sub => match (lhs_type, rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} + (PrimitiveType::Integer(_), PrimitiveType::Pointer(_)) => {} + (PrimitiveType::Integer(_), PrimitiveType::Array(_)) => {} + + (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + + (PrimitiveType::Pointer(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Array(_), PrimitiveType::Integer(_)) => {} + + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + }, ExprBinaryOp::SubAssign => { if !lhs.is_address() { return Err(CompileError::NotAssignable); @@ -1697,65 +1629,30 @@ impl Context { if lhs.cv_type()?.const_ { return Err(CompileError::AssignToConst); } - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - } - ExprBinaryOp::Mul => { - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 => {} + match (lhs_type, rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} + (PrimitiveType::Integer(_), PrimitiveType::Pointer(_)) => {} + (PrimitiveType::Integer(_), PrimitiveType::Array(_)) => {} + + (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + + (PrimitiveType::Pointer(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Array(_), PrimitiveType::Integer(_)) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), } } + ExprBinaryOp::Mul => match (lhs_type, rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} + + (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + }, ExprBinaryOp::MulAssign => { if !lhs.is_address() { return Err(CompileError::NotAssignable); @@ -1763,61 +1660,25 @@ impl Context { if lhs.cv_type()?.const_ { return Err(CompileError::AssignToConst); } - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - } - ExprBinaryOp::Div => { - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 => {} + match (lhs_type, rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} + + (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), } } + ExprBinaryOp::Div => match (lhs_type, rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} + + (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + }, ExprBinaryOp::DivAssign => { if !lhs.is_address() { return Err(CompileError::NotAssignable); @@ -1825,61 +1686,21 @@ impl Context { if lhs.cv_type()?.const_ { return Err(CompileError::AssignToConst); } - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - } - ExprBinaryOp::Mod => { - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 => {} + match (lhs_type, rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} + + (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), } } + ExprBinaryOp::Mod => match (lhs_type, rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + }, ExprBinaryOp::ModAssign => { if !lhs.is_address() { return Err(CompileError::NotAssignable); @@ -1887,57 +1708,20 @@ impl Context { if lhs.cv_type()?.const_ { return Err(CompileError::AssignToConst); } - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 => {} + match (lhs_type, rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} + + (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + _ => return Err(CompileError::ArithmeticOpOnNonNumeric), } } - ExprBinaryOp::BitwiseAnd => { - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 => {} - _ => return Err(CompileError::BitwiseOpOnNonInteger), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 => {} - _ => return Err(CompileError::BitwiseOpOnNonInteger), - } - } + ExprBinaryOp::BitwiseAnd => match (lhs_type, rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + _ => return Err(CompileError::BitwiseOpOnNonInteger), + }, ExprBinaryOp::BitwiseAndAssign => { if !lhs.is_address() { return Err(CompileError::NotAssignable); @@ -1945,53 +1729,15 @@ impl Context { if lhs.cv_type()?.const_ { return Err(CompileError::AssignToConst); } - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 => {} - _ => return Err(CompileError::BitwiseOpOnNonInteger), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 => {} - _ => return Err(CompileError::BitwiseOpOnNonInteger), - } - } - ExprBinaryOp::BitwiseOr => { - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 => {} - _ => return Err(CompileError::BitwiseOpOnNonInteger), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 => {} + match (lhs_type, rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} _ => return Err(CompileError::BitwiseOpOnNonInteger), } } + ExprBinaryOp::BitwiseOr => match (lhs_type, rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + _ => return Err(CompileError::BitwiseOpOnNonInteger), + }, ExprBinaryOp::BitwiseOrAssign => { if !lhs.is_address() { return Err(CompileError::NotAssignable); @@ -2000,53 +1746,15 @@ impl Context { return Err(CompileError::AssignToConst); } - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 => {} - _ => return Err(CompileError::BitwiseOpOnNonInteger), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 => {} - _ => return Err(CompileError::BitwiseOpOnNonInteger), - } - } - ExprBinaryOp::BitwiseXor => { - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 => {} - _ => return Err(CompileError::BitwiseOpOnNonInteger), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 => {} + match (lhs_type, rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} _ => return Err(CompileError::BitwiseOpOnNonInteger), } } + ExprBinaryOp::BitwiseXor => match (lhs_type, rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + _ => return Err(CompileError::BitwiseOpOnNonInteger), + }, ExprBinaryOp::BitwiseXorAssign => { if !lhs.is_address() { return Err(CompileError::NotAssignable); @@ -2055,53 +1763,15 @@ impl Context { return Err(CompileError::AssignToConst); } - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 => {} - _ => return Err(CompileError::BitwiseOpOnNonInteger), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 => {} - _ => return Err(CompileError::BitwiseOpOnNonInteger), - } - } - ExprBinaryOp::ShiftLeft => { - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 => {} - _ => return Err(CompileError::BitwiseOpOnNonInteger), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 => {} + match (lhs_type, rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} _ => return Err(CompileError::BitwiseOpOnNonInteger), } } + ExprBinaryOp::ShiftLeft => match (lhs_type, rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + _ => return Err(CompileError::BitwiseOpOnNonInteger), + }, ExprBinaryOp::ShiftLeftAssign => { if !lhs.is_address() { return Err(CompileError::NotAssignable); @@ -2110,53 +1780,15 @@ impl Context { return Err(CompileError::AssignToConst); } - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 => {} - _ => return Err(CompileError::BitwiseOpOnNonInteger), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 => {} - _ => return Err(CompileError::BitwiseOpOnNonInteger), - } - } - ExprBinaryOp::ShiftRight => { - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 => {} - _ => return Err(CompileError::BitwiseOpOnNonInteger), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 => {} + match (lhs_type, rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} _ => return Err(CompileError::BitwiseOpOnNonInteger), } } + ExprBinaryOp::ShiftRight => match (lhs_type, rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + _ => return Err(CompileError::BitwiseOpOnNonInteger), + }, ExprBinaryOp::ShiftRightAssign => { if !lhs.is_address() { return Err(CompileError::NotAssignable); @@ -2165,275 +1797,103 @@ impl Context { return Err(CompileError::AssignToConst); } - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 => {} - _ => return Err(CompileError::BitwiseOpOnNonInteger), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 => {} + match (lhs_type, rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} _ => return Err(CompileError::BitwiseOpOnNonInteger), } } - ExprBinaryOp::Equal => { - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - } - ExprBinaryOp::NotEqual => { - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - } - ExprBinaryOp::LessThan => { - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - } - ExprBinaryOp::LessThanOrEqual => { - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - } - ExprBinaryOp::GreaterThan => { - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - } - ExprBinaryOp::GreaterThanOrEqual => { - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - } + ExprBinaryOp::Equal => match (&lhs_type, &rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} + + (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + + (PrimitiveType::Pointer(_), PrimitiveType::Pointer(_)) => {} + (PrimitiveType::Pointer(_), PrimitiveType::Array(_)) => {} + (PrimitiveType::Array(_), PrimitiveType::Pointer(_)) => {} + (PrimitiveType::Array(_), PrimitiveType::Array(_)) => {} + + _ => return Err(CompileError::InvalidOperandType(lhs_type, rhs_type)), + }, + ExprBinaryOp::NotEqual => match (&lhs_type, &rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} + + (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + + (PrimitiveType::Pointer(_), PrimitiveType::Pointer(_)) => {} + (PrimitiveType::Pointer(_), PrimitiveType::Array(_)) => {} + (PrimitiveType::Array(_), PrimitiveType::Pointer(_)) => {} + (PrimitiveType::Array(_), PrimitiveType::Array(_)) => {} + + _ => return Err(CompileError::InvalidOperandType(lhs_type, rhs_type)), + }, + ExprBinaryOp::LessThan => match (&lhs_type, &rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} + + (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + + (PrimitiveType::Pointer(_), PrimitiveType::Pointer(_)) => {} + (PrimitiveType::Pointer(_), PrimitiveType::Array(_)) => {} + (PrimitiveType::Array(_), PrimitiveType::Pointer(_)) => {} + (PrimitiveType::Array(_), PrimitiveType::Array(_)) => {} + + _ => return Err(CompileError::InvalidOperandType(lhs_type, rhs_type)), + }, + ExprBinaryOp::LessThanOrEqual => match (&lhs_type, &rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} + + (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + + (PrimitiveType::Pointer(_), PrimitiveType::Pointer(_)) => {} + (PrimitiveType::Pointer(_), PrimitiveType::Array(_)) => {} + (PrimitiveType::Array(_), PrimitiveType::Pointer(_)) => {} + (PrimitiveType::Array(_), PrimitiveType::Array(_)) => {} + + _ => return Err(CompileError::InvalidOperandType(lhs_type, rhs_type)), + }, + ExprBinaryOp::GreaterThan => match (&lhs_type, &rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} + + (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + + (PrimitiveType::Pointer(_), PrimitiveType::Pointer(_)) => {} + (PrimitiveType::Pointer(_), PrimitiveType::Array(_)) => {} + (PrimitiveType::Array(_), PrimitiveType::Pointer(_)) => {} + (PrimitiveType::Array(_), PrimitiveType::Array(_)) => {} + + _ => return Err(CompileError::InvalidOperandType(lhs_type, rhs_type)), + }, + ExprBinaryOp::GreaterThanOrEqual => match (&lhs_type, &rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} + + (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + + (PrimitiveType::Pointer(_), PrimitiveType::Pointer(_)) => {} + (PrimitiveType::Pointer(_), PrimitiveType::Array(_)) => {} + (PrimitiveType::Array(_), PrimitiveType::Pointer(_)) => {} + (PrimitiveType::Array(_), PrimitiveType::Array(_)) => {} + + _ => return Err(CompileError::InvalidOperandType(lhs_type, rhs_type)), + }, ExprBinaryOp::LogicalAnd => { - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} - _ => return Err(CompileError::LogicalOpOnNonBool), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} - _ => return Err(CompileError::LogicalOpOnNonBool), + if !lhs_type.is_bool_castable() || !rhs_type.is_bool_castable() { + return Err(CompileError::LogicalOpOnNonBool); } } ExprBinaryOp::LogicalOr => { - match lhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} - _ => return Err(CompileError::LogicalOpOnNonBool), - } - match rhs_type { - PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => {} - _ => return Err(CompileError::LogicalOpOnNonBool), + if !lhs_type.is_bool_castable() || !rhs_type.is_bool_castable() { + return Err(CompileError::LogicalOpOnNonBool); } } @@ -2445,9 +1905,8 @@ impl Context { if lhs.cv_type()?.const_ { return Err(CompileError::AssignToConst); } - match lhs_type { - PrimitiveType::Array(_) => return Err(CompileError::AssignToArray), - _ => {} + if !rhs_type.is_implicitly_castable(&lhs_type) { + return Err(CompileError::InvalidOperandType(lhs_type, rhs_type)); } } } @@ -2591,15 +2050,9 @@ impl Context { if let Some(expr) = def.value { let expr = self.process_expression(expr)?; let value = match expr { - Expression::I8(v) => v as i64, - Expression::I16(v) => v as i64, - Expression::I32(v) => v as i64, - Expression::I64(v) => v, - Expression::U8(v) => v as i64, - Expression::U16(v) => v as i64, - Expression::U32(v) => v as i64, - Expression::U64(v) => v as i64, - _ => return Err(CompileError::ArraySizeNotInteger), + Expression::Signed(v, _) => v, + Expression::Unsigned(v, _) => v as i64, + _ => return Err(CompileError::EnumValueNotInteger), }; members.push((def.name, Some(value))); } else { @@ -2770,15 +2223,9 @@ impl Context { if let Some(expr) = def.value { let expr = self.process_expression(expr)?; let value = match expr { - Expression::I8(v) => v as i64, - Expression::I16(v) => v as i64, - Expression::I32(v) => v as i64, - Expression::I64(v) => v, - Expression::U8(v) => v as i64, - Expression::U16(v) => v as i64, - Expression::U32(v) => v as i64, - Expression::U64(v) => v as i64, - _ => return Err(CompileError::ArraySizeNotInteger), + Expression::Signed(v, _) => v, + Expression::Unsigned(v, _) => v as i64, + _ => return Err(CompileError::EnumValueNotInteger), }; members.push((def.name, Some(value))); } else { @@ -2858,38 +2305,14 @@ impl Context { ) -> Result { let size = self.process_expression(decl.size)?; let size = match size { - Expression::I8(v) => { - if v < 0 { - return Err(CompileError::NegativeArraySize); - } else { - v as usize - } - } - Expression::I16(v) => { - if v < 0 { - return Err(CompileError::NegativeArraySize); - } else { - v as usize - } - } - Expression::I32(v) => { - if v < 0 { - return Err(CompileError::NegativeArraySize); - } else { - v as usize - } - } - Expression::I64(v) => { + Expression::Signed(v, _) => { if v < 0 { return Err(CompileError::NegativeArraySize); } else { v as usize } } - Expression::U8(v) => v as usize, - Expression::U16(v) => v as usize, - Expression::U32(v) => v as usize, - Expression::U64(v) => v as usize, + Expression::Unsigned(v, _) => v as usize, _ => return Err(CompileError::ArraySizeNotInteger), }; if let Some(decl) = decl.declarator { diff --git a/src/ast2/declarator.rs b/src/ast2/declarator.rs index 4080887..c69e3c8 100644 --- a/src/ast2/declarator.rs +++ b/src/ast2/declarator.rs @@ -1,5 +1,7 @@ use super::CVType; use super::CompileError; +use super::Float; +use super::Integer; use super::PrimitiveType; #[derive(Debug, Clone)] @@ -190,32 +192,32 @@ impl SpecifierQualifierCollector { if self.void { CVType::from_primitive(PrimitiveType::Void) } else if self.float { - CVType::from_primitive(PrimitiveType::Float32) + CVType::from_primitive(PrimitiveType::Float(Float::Float32)) } else if self.double { - CVType::from_primitive(PrimitiveType::Float64) + CVType::from_primitive(PrimitiveType::Float(Float::Float64)) } else if self.char { if self.unsigned { - CVType::from_primitive(PrimitiveType::UInt8) + CVType::from_primitive(PrimitiveType::Integer(Integer::UInt8)) } else { - CVType::from_primitive(PrimitiveType::Int8) + CVType::from_primitive(PrimitiveType::Integer(Integer::Int8)) } } else if self.short { if self.unsigned { - CVType::from_primitive(PrimitiveType::UInt16) + CVType::from_primitive(PrimitiveType::Integer(Integer::UInt16)) } else { - CVType::from_primitive(PrimitiveType::Int16) + CVType::from_primitive(PrimitiveType::Integer(Integer::Int16)) } } else if self.long { if self.unsigned { - CVType::from_primitive(PrimitiveType::UInt64) + CVType::from_primitive(PrimitiveType::Integer(Integer::UInt64)) } else { - CVType::from_primitive(PrimitiveType::Int64) + CVType::from_primitive(PrimitiveType::Integer(Integer::Int64)) } } else if self.int { if self.unsigned { - CVType::from_primitive(PrimitiveType::UInt32) + CVType::from_primitive(PrimitiveType::Integer(Integer::UInt32)) } else { - CVType::from_primitive(PrimitiveType::Int32) + CVType::from_primitive(PrimitiveType::Integer(Integer::Int32)) } } else { match self.type_ { diff --git a/src/ast2/error.rs b/src/ast2/error.rs index 7e9b3b8..11a5c01 100644 --- a/src/ast2/error.rs +++ b/src/ast2/error.rs @@ -1,3 +1,5 @@ +use super::PrimitiveType; + #[derive(Debug, Clone)] pub enum CompileError { InvalidCase, @@ -79,4 +81,17 @@ pub enum CompileError { NotAssignable, AssignToArray, AssignToConst, + + /// not possible type cast from PrimitiveType to PrimitiveType + InvalidCast(PrimitiveType, PrimitiveType), + + /// there is no common type between PrimitiveType and PrimitiveType for operation + NoCommonType(PrimitiveType, PrimitiveType), + + CallWithWrongNumberOfArguments, + CallWithWrongArgumentType, + + InvalidOperandType(PrimitiveType, PrimitiveType), + + EnumValueNotInteger, } diff --git a/src/ast2/expression.rs b/src/ast2/expression.rs index 6839f0d..5e4d866 100644 --- a/src/ast2/expression.rs +++ b/src/ast2/expression.rs @@ -1,21 +1,16 @@ use crate::ast; use super::CompileError; +use super::Float; +use super::Integer; use super::PrimitiveType; use super::{CVType, VariableInfo}; #[derive(Debug, Clone)] pub enum Expression { - I8(i8), - I16(i16), - I32(i32), - I64(i64), - U8(u8), - U16(u16), - U32(u32), - U64(u64), - F32(f32), - F64(f64), + Signed(i64, Integer), + Unsigned(u64, Integer), + Float(f64, Float), String(String), Variable(VariableInfo), @@ -35,16 +30,9 @@ impl Expression { /// is this expression returns an address upon generating instructions? pub fn is_address(&self) -> bool { match self { - Expression::I8(_) - | Expression::I16(_) - | Expression::I32(_) - | Expression::I64(_) - | Expression::U8(_) - | Expression::U16(_) - | Expression::U32(_) - | Expression::U64(_) - | Expression::F32(_) - | Expression::F64(_) => false, + Expression::Signed(_, _) | Expression::Unsigned(_, _) | Expression::Float(_, _) => { + false + } Expression::String(_) => unimplemented!("is_address - String literal"), Expression::Variable(_) => true, Expression::Conditional(_) => false, @@ -64,24 +52,17 @@ impl Expression { pub fn cv_type(&self) -> Result { Ok(match self { Expression::Variable(var) => var.cv_type.clone(), - Expression::I8(_) => CVType::from_primitive(PrimitiveType::Int8), - Expression::I16(_) => CVType::from_primitive(PrimitiveType::Int16), - Expression::I32(_) => CVType::from_primitive(PrimitiveType::Int32), - Expression::I64(_) => CVType::from_primitive(PrimitiveType::Int64), - Expression::U8(_) => CVType::from_primitive(PrimitiveType::UInt8), - Expression::U16(_) => CVType::from_primitive(PrimitiveType::UInt16), - Expression::U32(_) => CVType::from_primitive(PrimitiveType::UInt32), - Expression::U64(_) => CVType::from_primitive(PrimitiveType::UInt64), - Expression::F32(_) => CVType::from_primitive(PrimitiveType::Float32), - Expression::F64(_) => CVType::from_primitive(PrimitiveType::Float64), + Expression::Signed(_, i) => CVType::from_primitive(PrimitiveType::Integer(*i)), + Expression::Unsigned(_, i) => CVType::from_primitive(PrimitiveType::Integer(*i)), + Expression::Float(_, f) => CVType::from_primitive(PrimitiveType::Float(*f)), Expression::String(_) => { CVType::from_primitive(PrimitiveType::Pointer(Box::new(CVType { - type_: PrimitiveType::Int8, + type_: PrimitiveType::Integer(Integer::Int8), const_: true, volatile: false, }))) } - Expression::Cast(expr) => expr.type_.clone(), + Expression::Cast(expr) => CVType::from_primitive(expr.type_.clone()), Expression::Bracket(expr) => match expr.src.cv_type()?.type_ { PrimitiveType::Pointer(t) => *t, PrimitiveType::Array(t) => *t.cv_type, @@ -94,103 +75,30 @@ impl Expression { .common_type(&expr.then_expr.cv_type()?.type_) .unwrap(), ), + Expression::Member(expr) => expr.member_type.clone(), + Expression::Arrow(expr) => expr.member_type.clone(), Expression::InitializerList(expr) => unimplemented!("expression_type InitializerList"), Expression::Paren(expr) => match expr.src.cv_type()?.type_ { PrimitiveType::Function(func) => *func.return_type, _ => unreachable!("Paren expression type"), }, - Expression::Binary(expr) => match expr.op { - ExprBinaryOp::Add => CVType::from_primitive( - expr.lhs - .cv_type()? - .type_ - .common_type(&expr.rhs.cv_type()?.type_) - .unwrap(), - ), - ExprBinaryOp::AddAssign => expr.lhs.cv_type()?, - ExprBinaryOp::Sub => CVType::from_primitive( - expr.lhs - .cv_type()? - .type_ - .common_type(&expr.rhs.cv_type()?.type_) - .unwrap(), - ), - ExprBinaryOp::SubAssign => expr.lhs.cv_type()?, - ExprBinaryOp::Mul => CVType::from_primitive( - expr.lhs - .cv_type()? - .type_ - .common_type(&expr.rhs.cv_type()?.type_) - .unwrap(), - ), - ExprBinaryOp::MulAssign => expr.lhs.cv_type()?, - ExprBinaryOp::Div => CVType::from_primitive( - expr.lhs - .cv_type()? - .type_ - .common_type(&expr.rhs.cv_type()?.type_) - .unwrap(), - ), - ExprBinaryOp::DivAssign => expr.lhs.cv_type()?, - ExprBinaryOp::Mod => CVType::from_primitive( - expr.lhs - .cv_type()? - .type_ - .common_type(&expr.rhs.cv_type()?.type_) - .unwrap(), - ), - ExprBinaryOp::ModAssign => expr.lhs.cv_type()?, - ExprBinaryOp::BitwiseAnd => CVType::from_primitive( - expr.lhs - .cv_type()? - .type_ - .bit_common_type(&expr.rhs.cv_type()?.type_) - .unwrap(), - ), - ExprBinaryOp::BitwiseAndAssign => expr.lhs.cv_type()?, - ExprBinaryOp::BitwiseOr => CVType::from_primitive( - expr.lhs - .cv_type()? - .type_ - .bit_common_type(&expr.rhs.cv_type()?.type_) - .unwrap(), - ), - ExprBinaryOp::BitwiseOrAssign => expr.lhs.cv_type()?, - ExprBinaryOp::BitwiseXor => CVType::from_primitive( - expr.lhs - .cv_type()? - .type_ - .bit_common_type(&expr.rhs.cv_type()?.type_) - .unwrap(), - ), - ExprBinaryOp::BitwiseXorAssign => expr.lhs.cv_type()?, - ExprBinaryOp::ShiftLeft => CVType::from_primitive(expr.lhs.cv_type()?.type_), - ExprBinaryOp::ShiftLeftAssign => expr.lhs.cv_type()?, - ExprBinaryOp::ShiftRight => CVType::from_primitive(expr.lhs.cv_type()?.type_), - ExprBinaryOp::ShiftRightAssign => expr.lhs.cv_type()?, - ExprBinaryOp::Equal => CVType::from_primitive(PrimitiveType::Int32), - ExprBinaryOp::NotEqual => CVType::from_primitive(PrimitiveType::Int32), - ExprBinaryOp::LessThan => CVType::from_primitive(PrimitiveType::Int32), - ExprBinaryOp::LessThanOrEqual => CVType::from_primitive(PrimitiveType::Int32), - ExprBinaryOp::GreaterThan => CVType::from_primitive(PrimitiveType::Int32), - ExprBinaryOp::GreaterThanOrEqual => CVType::from_primitive(PrimitiveType::Int32), - ExprBinaryOp::LogicalAnd => CVType::from_primitive(PrimitiveType::Int32), - ExprBinaryOp::LogicalOr => CVType::from_primitive(PrimitiveType::Int32), - ExprBinaryOp::Comma => expr.rhs.cv_type()?, - ExprBinaryOp::Assign => expr.lhs.cv_type()?, - }, Expression::Unary(expr) => match expr.op { ExprUnaryOp::AddressOf => { CVType::from_primitive(PrimitiveType::Pointer(Box::new(expr.expr.cv_type()?))) } - ExprUnaryOp::BitwiseNot => { - CVType::from_primitive(expr.expr.cv_type()?.type_.to_unsigned().unwrap()) - } + ExprUnaryOp::BitwiseNot => match expr.expr.cv_type()?.type_ { + PrimitiveType::Integer(i) => { + CVType::from_primitive(PrimitiveType::Integer(i.to_unsigned())) + } + _ => unreachable!("BitwiseNot expression type"), + }, ExprUnaryOp::DecrementPost => CVType::from_primitive(expr.expr.cv_type()?.type_), ExprUnaryOp::DecrementPre => CVType::from_primitive(expr.expr.cv_type()?.type_), ExprUnaryOp::IncrementPost => CVType::from_primitive(expr.expr.cv_type()?.type_), ExprUnaryOp::IncrementPre => CVType::from_primitive(expr.expr.cv_type()?.type_), - ExprUnaryOp::LogicalNot => CVType::from_primitive(PrimitiveType::Int32), + ExprUnaryOp::LogicalNot => { + CVType::from_primitive(PrimitiveType::Integer(Integer::Int32)) + } ExprUnaryOp::Minus => CVType::from_primitive(expr.expr.cv_type()?.type_), ExprUnaryOp::Dereference => match expr.expr.cv_type()?.type_ { PrimitiveType::Pointer(t) => *t, @@ -199,8 +107,215 @@ impl Expression { }, ExprUnaryOp::Plus => CVType::from_primitive(expr.expr.cv_type()?.type_), }, - Expression::Member(expr) => expr.member_type.clone(), - Expression::Arrow(expr) => expr.member_type.clone(), + Expression::Binary(expr) => { + let lhs_type = expr.lhs.cv_type()?; + let rhs_type = expr.rhs.cv_type()?; + #[allow(unused)] + match expr.op { + ExprBinaryOp::Add => { + let type_ = match (lhs_type.type_, rhs_type.type_) { + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + PrimitiveType::Integer(a.common_type(&b)) + } + (PrimitiveType::Integer(_), PrimitiveType::Float(b)) => { + PrimitiveType::Float(b) + } + (PrimitiveType::Integer(_), PrimitiveType::Pointer(b)) => { + PrimitiveType::Pointer(b) + } + (PrimitiveType::Integer(_), PrimitiveType::Array(b)) => { + PrimitiveType::Pointer(b.cv_type) + } + + (PrimitiveType::Float(a), PrimitiveType::Integer(_)) => { + PrimitiveType::Float(a) + } + (PrimitiveType::Float(a), PrimitiveType::Float(b)) => { + PrimitiveType::Float(a.common_type(&b)) + } + + (PrimitiveType::Pointer(a), PrimitiveType::Integer(b)) => { + PrimitiveType::Pointer(a) + } + (PrimitiveType::Array(a), PrimitiveType::Integer(b)) => { + PrimitiveType::Pointer(a.cv_type) + } + + _ => unreachable!("Add expression type"), + }; + CVType::from_primitive(type_) + } + ExprBinaryOp::AddAssign => lhs_type, + ExprBinaryOp::Sub => { + let type_ = match (lhs_type.type_, rhs_type.type_) { + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + PrimitiveType::Integer(a.common_type(&b)) + } + (PrimitiveType::Integer(a), PrimitiveType::Float(b)) => { + PrimitiveType::Float(b) + } + (PrimitiveType::Integer(a), PrimitiveType::Pointer(b)) => { + PrimitiveType::Pointer(b) + } + (PrimitiveType::Integer(a), PrimitiveType::Array(b)) => { + PrimitiveType::Pointer(b.cv_type) + } + + (PrimitiveType::Float(a), PrimitiveType::Integer(b)) => { + PrimitiveType::Float(a) + } + (PrimitiveType::Float(a), PrimitiveType::Float(b)) => { + PrimitiveType::Float(a.common_type(&b)) + } + + (PrimitiveType::Pointer(a), PrimitiveType::Integer(b)) => { + PrimitiveType::Pointer(a) + } + (PrimitiveType::Array(a), PrimitiveType::Integer(b)) => { + PrimitiveType::Pointer(a.cv_type) + } + + _ => unreachable!("Sub expression type"), + }; + CVType::from_primitive(type_) + } + ExprBinaryOp::SubAssign => lhs_type, + ExprBinaryOp::Mul => { + let type_ = match (lhs_type.type_, rhs_type.type_) { + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + PrimitiveType::Integer(a.common_type(&b)) + } + (PrimitiveType::Integer(a), PrimitiveType::Float(b)) => { + PrimitiveType::Float(b) + } + + (PrimitiveType::Float(a), PrimitiveType::Integer(b)) => { + PrimitiveType::Float(a) + } + (PrimitiveType::Float(a), PrimitiveType::Float(b)) => { + PrimitiveType::Float(a.common_type(&b)) + } + + _ => unreachable!("Mul expression type"), + }; + CVType::from_primitive(type_) + } + ExprBinaryOp::MulAssign => lhs_type, + ExprBinaryOp::Div => { + let type_ = match (lhs_type.type_, rhs_type.type_) { + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + PrimitiveType::Integer(a.common_type(&b)) + } + (PrimitiveType::Integer(a), PrimitiveType::Float(b)) => { + PrimitiveType::Float(b) + } + + (PrimitiveType::Float(a), PrimitiveType::Integer(b)) => { + PrimitiveType::Float(a) + } + (PrimitiveType::Float(a), PrimitiveType::Float(b)) => { + PrimitiveType::Float(a.common_type(&b)) + } + + _ => unreachable!("Div expression type"), + }; + CVType::from_primitive(type_) + } + ExprBinaryOp::DivAssign => lhs_type, + ExprBinaryOp::Mod => { + let type_ = match (lhs_type.type_, rhs_type.type_) { + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + PrimitiveType::Integer(a.common_type(&b)) + } + + _ => unreachable!("Mod expression type"), + }; + CVType::from_primitive(type_) + } + ExprBinaryOp::ModAssign => lhs_type, + ExprBinaryOp::BitwiseAnd => { + let type_ = match (lhs_type.type_, rhs_type.type_) { + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + PrimitiveType::Integer(a.common_type(&b)) + } + + _ => unreachable!("BitAnd expression type"), + }; + CVType::from_primitive(type_) + } + ExprBinaryOp::BitwiseAndAssign => lhs_type, + ExprBinaryOp::BitwiseOr => { + let type_ = match (lhs_type.type_, rhs_type.type_) { + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + PrimitiveType::Integer(a.common_type(&b)) + } + + _ => unreachable!("BitOr expression type"), + }; + CVType::from_primitive(type_) + } + ExprBinaryOp::BitwiseOrAssign => lhs_type, + ExprBinaryOp::BitwiseXor => { + let type_ = match (lhs_type.type_, rhs_type.type_) { + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + PrimitiveType::Integer(a.common_type(&b)) + } + + _ => unreachable!("BitAnd expression type"), + }; + CVType::from_primitive(type_) + } + ExprBinaryOp::BitwiseXorAssign => lhs_type, + ExprBinaryOp::ShiftLeft => { + let type_ = match (lhs_type.type_, rhs_type.type_) { + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + PrimitiveType::Integer(a.common_type(&b)) + } + + _ => unreachable!("BitAnd expression type"), + }; + CVType::from_primitive(type_) + } + ExprBinaryOp::ShiftLeftAssign => lhs_type, + ExprBinaryOp::ShiftRight => { + let type_ = match (lhs_type.type_, rhs_type.type_) { + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + PrimitiveType::Integer(a.common_type(&b)) + } + + _ => unreachable!("BitAnd expression type"), + }; + CVType::from_primitive(type_) + } + ExprBinaryOp::ShiftRightAssign => lhs_type, + ExprBinaryOp::Equal => { + CVType::from_primitive(PrimitiveType::Integer(Integer::Int32)) + } + ExprBinaryOp::NotEqual => { + CVType::from_primitive(PrimitiveType::Integer(Integer::Int32)) + } + ExprBinaryOp::LessThan => { + CVType::from_primitive(PrimitiveType::Integer(Integer::Int32)) + } + ExprBinaryOp::LessThanOrEqual => { + CVType::from_primitive(PrimitiveType::Integer(Integer::Int32)) + } + ExprBinaryOp::GreaterThan => { + CVType::from_primitive(PrimitiveType::Integer(Integer::Int32)) + } + ExprBinaryOp::GreaterThanOrEqual => { + CVType::from_primitive(PrimitiveType::Integer(Integer::Int32)) + } + ExprBinaryOp::LogicalAnd => { + CVType::from_primitive(PrimitiveType::Integer(Integer::Int32)) + } + ExprBinaryOp::LogicalOr => { + CVType::from_primitive(PrimitiveType::Integer(Integer::Int32)) + } + ExprBinaryOp::Comma => rhs_type, + ExprBinaryOp::Assign => lhs_type, + } + } }) } } @@ -215,7 +330,7 @@ pub struct ExprConditional { #[derive(Debug, Clone)] pub struct ExprCast { pub expr: Box, - pub type_: CVType, + pub type_: PrimitiveType, } #[derive(Debug, Clone)] diff --git a/src/ast2/mod.rs b/src/ast2/mod.rs index 1195c4c..1e02768 100644 --- a/src/ast2/mod.rs +++ b/src/ast2/mod.rs @@ -49,7 +49,9 @@ pub use typename::ArrayType; pub use typename::CVType; pub use typename::EnumMember; pub use typename::EnumType; +pub use typename::Float; pub use typename::FunctionType; +pub use typename::Integer; pub use typename::PrimitiveType; pub use typename::StorageQualifier; pub use typename::StructMember; diff --git a/src/ast2/typename.rs b/src/ast2/typename.rs index 9aa76cc..747fc3f 100644 --- a/src/ast2/typename.rs +++ b/src/ast2/typename.rs @@ -1,8 +1,7 @@ use super::CompileError; -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub enum PrimitiveType { - Void, +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Copy)] +pub enum Integer { UInt8, UInt16, UInt32, @@ -11,308 +10,139 @@ pub enum PrimitiveType { Int16, Int32, Int64, - Float32, - Float64, - - Struct(StructType), - Union(StructType), - Enum(EnumType), - - Pointer(Box), - Array(ArrayType), - Function(FunctionType), } -impl PrimitiveType { - pub fn is_integer(&self) -> bool { +impl Integer { + pub fn is_signed(&self) -> bool { matches!( self, - PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 + Integer::Int8 | Integer::Int16 | Integer::Int32 | Integer::Int64 ) } - pub fn is_numeric(&self) -> bool { + pub fn is_unsigned(&self) -> bool { matches!( self, - PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::Float32 - | PrimitiveType::Float64 + Integer::UInt8 | Integer::UInt16 | Integer::UInt32 | Integer::UInt64 ) } - pub fn is_float(&self) -> bool { - matches!(self, PrimitiveType::Float32 | PrimitiveType::Float64) + pub fn to_unsigned(&self) -> Self { + match self { + Integer::Int8 => Integer::UInt8, + Integer::Int16 => Integer::UInt16, + Integer::Int32 => Integer::UInt32, + Integer::Int64 => Integer::UInt64, + _ => *self, + } } - pub fn is_struct(&self) -> bool { - matches!(self, PrimitiveType::Struct(_)) + pub fn sizeof(&self) -> usize { + match self { + Integer::UInt8 | Integer::Int8 => 1, + Integer::UInt16 | Integer::Int16 => 2, + Integer::UInt32 | Integer::Int32 => 4, + Integer::UInt64 | Integer::Int64 => 8, + } } - pub fn is_union(&self) -> bool { - matches!(self, PrimitiveType::Union(_)) + pub fn alignof(&self) -> usize { + match self { + Integer::UInt8 | Integer::Int8 => 1, + Integer::UInt16 | Integer::Int16 => 2, + Integer::UInt32 | Integer::Int32 => 4, + Integer::UInt64 | Integer::Int64 => 8, + } } - pub fn is_enum(&self) -> bool { - matches!(self, PrimitiveType::Enum(_)) + pub fn from_size_signed(size: usize, unsigned: bool) -> Self { + match (size, unsigned) { + (1, true) => Integer::UInt8, + (2, true) => Integer::UInt16, + (4, true) => Integer::UInt32, + (8, true) => Integer::UInt64, + (1, false) => Integer::Int8, + (2, false) => Integer::Int16, + (4, false) => Integer::Int32, + (8, false) => Integer::Int64, + _ => panic!("Invalid size"), + } } - - pub fn is_bool_castable(&self) -> bool { + pub fn common_type(&self, other: &Integer) -> Self { + let size = self.sizeof().max(other.sizeof()); + let unsigned = self.is_unsigned() || other.is_unsigned(); + Integer::from_size_signed(size, unsigned) + } +} +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Copy)] +pub enum Float { + Float32, + Float64, +} +impl Float { + pub fn sizeof(&self) -> usize { match self { - PrimitiveType::UInt8 - | PrimitiveType::UInt16 - | PrimitiveType::UInt32 - | PrimitiveType::UInt64 - | PrimitiveType::Int8 - | PrimitiveType::Int16 - | PrimitiveType::Int32 - | PrimitiveType::Int64 - | PrimitiveType::Pointer(_) - | PrimitiveType::Array(_) => true, - PrimitiveType::Enum(enum_type) => enum_type.type_.is_bool_castable(), - _ => false, + Float::Float32 => 4, + Float::Float64 => 8, } } - pub fn bit_common_type(&self, other: &Self) -> Option { - let lhs = match self { - PrimitiveType::UInt8 => 0, - PrimitiveType::UInt16 => 1, - PrimitiveType::UInt32 => 2, - PrimitiveType::UInt64 => 3, - PrimitiveType::Int8 => 0, - PrimitiveType::Int16 => 1, - PrimitiveType::Int32 => 2, - PrimitiveType::Int64 => 3, - _ => return None, - }; - let rhs = match other { - PrimitiveType::UInt8 => 0, - PrimitiveType::UInt16 => 1, - PrimitiveType::UInt32 => 2, - PrimitiveType::UInt64 => 3, - PrimitiveType::Int8 => 0, - PrimitiveType::Int16 => 1, - PrimitiveType::Int32 => 2, - PrimitiveType::Int64 => 3, - _ => return None, - }; - let common = lhs.max(rhs); - match common { - 0 => Some(PrimitiveType::UInt8), - 1 => Some(PrimitiveType::UInt16), - 2 => Some(PrimitiveType::UInt32), - 3 => Some(PrimitiveType::UInt64), - _ => unreachable!(), + pub fn alignof(&self) -> usize { + match self { + Float::Float32 => 4, + Float::Float64 => 8, } } - pub fn common_type(&self, other: &Self) -> Option { + pub fn from_size(size: usize) -> Self { + match size { + 4 => Float::Float32, + 8 => Float::Float64, + _ => panic!("Invalid size"), + } + } + pub fn common_type(&self, other: &Float) -> Self { match (self, other) { - (PrimitiveType::UInt8, PrimitiveType::UInt8) => Some(PrimitiveType::UInt8), - (PrimitiveType::UInt8, PrimitiveType::UInt16) => Some(PrimitiveType::UInt16), - (PrimitiveType::UInt8, PrimitiveType::UInt32) => Some(PrimitiveType::UInt32), - (PrimitiveType::UInt8, PrimitiveType::UInt64) => Some(PrimitiveType::UInt64), - (PrimitiveType::UInt8, PrimitiveType::Int8) => Some(PrimitiveType::UInt8), - (PrimitiveType::UInt8, PrimitiveType::Int16) => Some(PrimitiveType::UInt16), - (PrimitiveType::UInt8, PrimitiveType::Int32) => Some(PrimitiveType::UInt32), - (PrimitiveType::UInt8, PrimitiveType::Int64) => Some(PrimitiveType::UInt64), - (PrimitiveType::UInt8, PrimitiveType::Float32) => Some(PrimitiveType::Float32), - (PrimitiveType::UInt8, PrimitiveType::Float64) => Some(PrimitiveType::Float64), - (PrimitiveType::UInt8, PrimitiveType::Array(t)) => Some(t.cv_type.type_.clone()), - (PrimitiveType::UInt8, PrimitiveType::Pointer(t)) => Some(t.as_ref().type_.clone()), - (PrimitiveType::UInt8, _) => None, - - (PrimitiveType::UInt16, PrimitiveType::UInt8) => Some(PrimitiveType::UInt16), - (PrimitiveType::UInt16, PrimitiveType::UInt16) => Some(PrimitiveType::UInt16), - (PrimitiveType::UInt16, PrimitiveType::UInt32) => Some(PrimitiveType::UInt32), - (PrimitiveType::UInt16, PrimitiveType::UInt64) => Some(PrimitiveType::UInt64), - (PrimitiveType::UInt16, PrimitiveType::Int8) => Some(PrimitiveType::UInt16), - (PrimitiveType::UInt16, PrimitiveType::Int16) => Some(PrimitiveType::UInt16), - (PrimitiveType::UInt16, PrimitiveType::Int32) => Some(PrimitiveType::UInt32), - (PrimitiveType::UInt16, PrimitiveType::Int64) => Some(PrimitiveType::UInt64), - (PrimitiveType::UInt16, PrimitiveType::Float32) => Some(PrimitiveType::Float32), - (PrimitiveType::UInt16, PrimitiveType::Float64) => Some(PrimitiveType::Float64), - (PrimitiveType::UInt16, PrimitiveType::Array(t)) => Some(t.cv_type.type_.clone()), - (PrimitiveType::UInt16, PrimitiveType::Pointer(t)) => Some(t.as_ref().type_.clone()), - (PrimitiveType::UInt16, _) => None, - - (PrimitiveType::UInt32, PrimitiveType::UInt8) => Some(PrimitiveType::UInt32), - (PrimitiveType::UInt32, PrimitiveType::UInt16) => Some(PrimitiveType::UInt32), - (PrimitiveType::UInt32, PrimitiveType::UInt32) => Some(PrimitiveType::UInt32), - (PrimitiveType::UInt32, PrimitiveType::UInt64) => Some(PrimitiveType::UInt64), - (PrimitiveType::UInt32, PrimitiveType::Int8) => Some(PrimitiveType::UInt32), - (PrimitiveType::UInt32, PrimitiveType::Int16) => Some(PrimitiveType::UInt32), - (PrimitiveType::UInt32, PrimitiveType::Int32) => Some(PrimitiveType::UInt32), - (PrimitiveType::UInt32, PrimitiveType::Int64) => Some(PrimitiveType::UInt64), - (PrimitiveType::UInt32, PrimitiveType::Float32) => Some(PrimitiveType::Float32), - (PrimitiveType::UInt32, PrimitiveType::Float64) => Some(PrimitiveType::Float64), - (PrimitiveType::UInt32, PrimitiveType::Array(t)) => Some(t.cv_type.type_.clone()), - (PrimitiveType::UInt32, PrimitiveType::Pointer(t)) => Some(t.as_ref().type_.clone()), - (PrimitiveType::UInt32, _) => None, - - (PrimitiveType::UInt64, PrimitiveType::UInt8) => Some(PrimitiveType::UInt64), - (PrimitiveType::UInt64, PrimitiveType::UInt16) => Some(PrimitiveType::UInt64), - (PrimitiveType::UInt64, PrimitiveType::UInt32) => Some(PrimitiveType::UInt64), - (PrimitiveType::UInt64, PrimitiveType::UInt64) => Some(PrimitiveType::UInt64), - (PrimitiveType::UInt64, PrimitiveType::Int8) => Some(PrimitiveType::UInt64), - (PrimitiveType::UInt64, PrimitiveType::Int16) => Some(PrimitiveType::UInt64), - (PrimitiveType::UInt64, PrimitiveType::Int32) => Some(PrimitiveType::UInt64), - (PrimitiveType::UInt64, PrimitiveType::Int64) => Some(PrimitiveType::UInt64), - (PrimitiveType::UInt64, PrimitiveType::Float32) => Some(PrimitiveType::Float32), - (PrimitiveType::UInt64, PrimitiveType::Float64) => Some(PrimitiveType::Float64), - (PrimitiveType::UInt64, PrimitiveType::Array(t)) => Some(t.cv_type.type_.clone()), - (PrimitiveType::UInt64, PrimitiveType::Pointer(t)) => Some(t.as_ref().type_.clone()), - (PrimitiveType::UInt64, _) => None, - - (PrimitiveType::Int8, PrimitiveType::UInt8) => Some(PrimitiveType::UInt8), - (PrimitiveType::Int8, PrimitiveType::UInt16) => Some(PrimitiveType::UInt16), - (PrimitiveType::Int8, PrimitiveType::UInt32) => Some(PrimitiveType::UInt32), - (PrimitiveType::Int8, PrimitiveType::UInt64) => Some(PrimitiveType::UInt64), - (PrimitiveType::Int8, PrimitiveType::Int8) => Some(PrimitiveType::UInt8), - (PrimitiveType::Int8, PrimitiveType::Int16) => Some(PrimitiveType::UInt16), - (PrimitiveType::Int8, PrimitiveType::Int32) => Some(PrimitiveType::UInt32), - (PrimitiveType::Int8, PrimitiveType::Int64) => Some(PrimitiveType::UInt64), - (PrimitiveType::Int8, PrimitiveType::Float32) => Some(PrimitiveType::Float32), - (PrimitiveType::Int8, PrimitiveType::Float64) => Some(PrimitiveType::Float64), - (PrimitiveType::Int8, PrimitiveType::Array(t)) => Some(t.cv_type.type_.clone()), - (PrimitiveType::Int8, PrimitiveType::Pointer(t)) => Some(t.as_ref().type_.clone()), - (PrimitiveType::Int8, _) => None, - - (PrimitiveType::Int16, PrimitiveType::UInt8) => Some(PrimitiveType::UInt16), - (PrimitiveType::Int16, PrimitiveType::UInt16) => Some(PrimitiveType::UInt16), - (PrimitiveType::Int16, PrimitiveType::UInt32) => Some(PrimitiveType::UInt32), - (PrimitiveType::Int16, PrimitiveType::UInt64) => Some(PrimitiveType::UInt64), - (PrimitiveType::Int16, PrimitiveType::Int8) => Some(PrimitiveType::UInt16), - (PrimitiveType::Int16, PrimitiveType::Int16) => Some(PrimitiveType::UInt16), - (PrimitiveType::Int16, PrimitiveType::Int32) => Some(PrimitiveType::UInt32), - (PrimitiveType::Int16, PrimitiveType::Int64) => Some(PrimitiveType::UInt64), - (PrimitiveType::Int16, PrimitiveType::Float32) => Some(PrimitiveType::Float32), - (PrimitiveType::Int16, PrimitiveType::Float64) => Some(PrimitiveType::Float64), - (PrimitiveType::Int16, PrimitiveType::Array(t)) => Some(t.cv_type.type_.clone()), - (PrimitiveType::Int16, PrimitiveType::Pointer(t)) => Some(t.as_ref().type_.clone()), - (PrimitiveType::Int16, _) => None, - - (PrimitiveType::Int32, PrimitiveType::UInt8) => Some(PrimitiveType::UInt32), - (PrimitiveType::Int32, PrimitiveType::UInt16) => Some(PrimitiveType::UInt32), - (PrimitiveType::Int32, PrimitiveType::UInt32) => Some(PrimitiveType::UInt32), - (PrimitiveType::Int32, PrimitiveType::UInt64) => Some(PrimitiveType::UInt64), - (PrimitiveType::Int32, PrimitiveType::Int8) => Some(PrimitiveType::UInt32), - (PrimitiveType::Int32, PrimitiveType::Int16) => Some(PrimitiveType::UInt32), - (PrimitiveType::Int32, PrimitiveType::Int32) => Some(PrimitiveType::UInt32), - (PrimitiveType::Int32, PrimitiveType::Int64) => Some(PrimitiveType::UInt64), - (PrimitiveType::Int32, PrimitiveType::Float32) => Some(PrimitiveType::Float32), - (PrimitiveType::Int32, PrimitiveType::Float64) => Some(PrimitiveType::Float64), - (PrimitiveType::Int32, PrimitiveType::Array(t)) => Some(t.cv_type.type_.clone()), - (PrimitiveType::Int32, PrimitiveType::Pointer(t)) => Some(t.as_ref().type_.clone()), - (PrimitiveType::Int32, _) => None, - - (PrimitiveType::Int64, PrimitiveType::UInt8) => Some(PrimitiveType::UInt64), - (PrimitiveType::Int64, PrimitiveType::UInt16) => Some(PrimitiveType::UInt64), - (PrimitiveType::Int64, PrimitiveType::UInt32) => Some(PrimitiveType::UInt64), - (PrimitiveType::Int64, PrimitiveType::UInt64) => Some(PrimitiveType::UInt64), - (PrimitiveType::Int64, PrimitiveType::Int8) => Some(PrimitiveType::UInt64), - (PrimitiveType::Int64, PrimitiveType::Int16) => Some(PrimitiveType::UInt64), - (PrimitiveType::Int64, PrimitiveType::Int32) => Some(PrimitiveType::UInt64), - (PrimitiveType::Int64, PrimitiveType::Int64) => Some(PrimitiveType::UInt64), - (PrimitiveType::Int64, PrimitiveType::Float32) => Some(PrimitiveType::Float32), - (PrimitiveType::Int64, PrimitiveType::Float64) => Some(PrimitiveType::Float64), - (PrimitiveType::Int64, PrimitiveType::Array(t)) => Some(t.cv_type.type_.clone()), - (PrimitiveType::Int64, PrimitiveType::Pointer(t)) => Some(t.as_ref().type_.clone()), - (PrimitiveType::Int64, _) => None, - - (PrimitiveType::Float32, PrimitiveType::UInt8) => Some(PrimitiveType::Float32), - (PrimitiveType::Float32, PrimitiveType::UInt16) => Some(PrimitiveType::Float32), - (PrimitiveType::Float32, PrimitiveType::UInt32) => Some(PrimitiveType::Float32), - (PrimitiveType::Float32, PrimitiveType::UInt64) => Some(PrimitiveType::Float32), - (PrimitiveType::Float32, PrimitiveType::Int8) => Some(PrimitiveType::Float32), - (PrimitiveType::Float32, PrimitiveType::Int16) => Some(PrimitiveType::Float32), - (PrimitiveType::Float32, PrimitiveType::Int32) => Some(PrimitiveType::Float32), - (PrimitiveType::Float32, PrimitiveType::Int64) => Some(PrimitiveType::Float32), - (PrimitiveType::Float32, PrimitiveType::Float32) => Some(PrimitiveType::Float32), - (PrimitiveType::Float32, PrimitiveType::Float64) => Some(PrimitiveType::Float64), - (PrimitiveType::Float32, _) => None, - - (PrimitiveType::Float64, PrimitiveType::UInt8) => Some(PrimitiveType::Float64), - (PrimitiveType::Float64, PrimitiveType::UInt16) => Some(PrimitiveType::Float64), - (PrimitiveType::Float64, PrimitiveType::UInt32) => Some(PrimitiveType::Float64), - (PrimitiveType::Float64, PrimitiveType::UInt64) => Some(PrimitiveType::Float64), - (PrimitiveType::Float64, PrimitiveType::Int8) => Some(PrimitiveType::Float64), - (PrimitiveType::Float64, PrimitiveType::Int16) => Some(PrimitiveType::Float64), - (PrimitiveType::Float64, PrimitiveType::Int32) => Some(PrimitiveType::Float64), - (PrimitiveType::Float64, PrimitiveType::Int64) => Some(PrimitiveType::Float64), - (PrimitiveType::Float64, PrimitiveType::Float32) => Some(PrimitiveType::Float64), - (PrimitiveType::Float64, PrimitiveType::Float64) => Some(PrimitiveType::Float64), - (PrimitiveType::Float64, _) => None, + (Float::Float64, _) => Float::Float64, + (_, Float::Float64) => Float::Float64, + _ => Float::Float32, + } + } +} - (PrimitiveType::Pointer(t), PrimitiveType::UInt8) => { - Some(PrimitiveType::Pointer(t.clone())) - } - (PrimitiveType::Pointer(t), PrimitiveType::UInt16) => { - Some(PrimitiveType::Pointer(t.clone())) - } - (PrimitiveType::Pointer(t), PrimitiveType::UInt32) => { - Some(PrimitiveType::Pointer(t.clone())) - } - (PrimitiveType::Pointer(t), PrimitiveType::UInt64) => { - Some(PrimitiveType::Pointer(t.clone())) - } - (PrimitiveType::Pointer(t), PrimitiveType::Int8) => { - Some(PrimitiveType::Pointer(t.clone())) - } - (PrimitiveType::Pointer(t), PrimitiveType::Int16) => { - Some(PrimitiveType::Pointer(t.clone())) - } - (PrimitiveType::Pointer(t), PrimitiveType::Int32) => { - Some(PrimitiveType::Pointer(t.clone())) - } - (PrimitiveType::Pointer(t), PrimitiveType::Int64) => { - Some(PrimitiveType::Pointer(t.clone())) - } - (PrimitiveType::Pointer(t), _) => None, +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub enum PrimitiveType { + Void, + Integer(Integer), + Float(Float), - (PrimitiveType::Array(t), PrimitiveType::UInt8) => { - Some(PrimitiveType::Pointer(t.cv_type.clone())) - } - (PrimitiveType::Array(t), PrimitiveType::UInt16) => { - Some(PrimitiveType::Pointer(t.cv_type.clone())) - } - (PrimitiveType::Array(t), PrimitiveType::UInt32) => { - Some(PrimitiveType::Pointer(t.cv_type.clone())) - } - (PrimitiveType::Array(t), PrimitiveType::UInt64) => { - Some(PrimitiveType::Pointer(t.cv_type.clone())) - } - (PrimitiveType::Array(t), PrimitiveType::Int8) => { - Some(PrimitiveType::Pointer(t.cv_type.clone())) - } - (PrimitiveType::Array(t), PrimitiveType::Int16) => { - Some(PrimitiveType::Pointer(t.cv_type.clone())) - } - (PrimitiveType::Array(t), PrimitiveType::Int32) => { - Some(PrimitiveType::Pointer(t.cv_type.clone())) - } - (PrimitiveType::Array(t), PrimitiveType::Int64) => { - Some(PrimitiveType::Pointer(t.cv_type.clone())) - } - (PrimitiveType::Array(t), _) => None, + Pointer(Box), + Array(ArrayType), - _ => None, - } + Struct(StructType), + Union(StructType), + Enum(EnumType), + Function(FunctionType), +} +impl PrimitiveType { + pub fn is_castable(&self, to: &PrimitiveType) -> bool { + unimplemented!("is_castable") + } + pub fn is_implicitly_castable(&self, to: &PrimitiveType) -> bool { + unimplemented!("is_implicitly_castable") + } + pub fn is_bool_castable(&self) -> bool { + matches!( + self, + PrimitiveType::Integer(_) | PrimitiveType::Pointer(_) | PrimitiveType::Array(_) + ) + } + pub fn is_struct(&self) -> bool { + matches!(self, PrimitiveType::Struct(_)) + } + pub fn is_union(&self) -> bool { + matches!(self, PrimitiveType::Union(_)) + } + pub fn is_enum(&self) -> bool { + matches!(self, PrimitiveType::Enum(_)) } - pub fn sizeof(&self) -> Result { Ok(match self { PrimitiveType::Void => return Err(CompileError::SizeofIncompleteType), - PrimitiveType::UInt8 | PrimitiveType::Int8 => 1, - PrimitiveType::UInt16 | PrimitiveType::Int16 => 2, - PrimitiveType::UInt32 | PrimitiveType::Int32 | PrimitiveType::Float32 => 4, - PrimitiveType::UInt64 | PrimitiveType::Int64 | PrimitiveType::Float64 => 8, + PrimitiveType::Integer(i) => i.sizeof(), + PrimitiveType::Float(f) => f.sizeof(), PrimitiveType::Pointer(_) => 8, PrimitiveType::Array(ArrayType { cv_type, size }) => cv_type.type_.sizeof()? * (*size), PrimitiveType::Function(_) => return Err(CompileError::SizeofIncompleteType), @@ -326,10 +156,8 @@ impl PrimitiveType { pub fn alignof(&self) -> Result { Ok(match self { PrimitiveType::Void => return Err(CompileError::SizeofIncompleteType), - PrimitiveType::UInt8 | PrimitiveType::Int8 => 1, - PrimitiveType::UInt16 | PrimitiveType::Int16 => 2, - PrimitiveType::UInt32 | PrimitiveType::Int32 | PrimitiveType::Float32 => 4, - PrimitiveType::UInt64 | PrimitiveType::Int64 | PrimitiveType::Float64 => 8, + PrimitiveType::Integer(i) => i.alignof(), + PrimitiveType::Float(f) => f.alignof(), PrimitiveType::Pointer(_) => 8, PrimitiveType::Array(ArrayType { cv_type, size: _ }) => cv_type.type_.alignof()?, PrimitiveType::Function(_) => return Err(CompileError::SizeofIncompleteType), @@ -340,17 +168,74 @@ impl PrimitiveType { PrimitiveType::Enum(e) => e.type_.alignof()?, }) } - pub fn to_unsigned(&self) -> Option { - match self { - PrimitiveType::Int8 => Some(PrimitiveType::UInt8), - PrimitiveType::Int16 => Some(PrimitiveType::UInt16), - PrimitiveType::Int32 => Some(PrimitiveType::UInt32), - PrimitiveType::Int64 => Some(PrimitiveType::UInt64), - PrimitiveType::UInt8 => Some(PrimitiveType::UInt8), - PrimitiveType::UInt16 => Some(PrimitiveType::UInt16), - PrimitiveType::UInt32 => Some(PrimitiveType::UInt32), - PrimitiveType::UInt64 => Some(PrimitiveType::UInt64), - _ => None, + + pub fn common_type(&self, other: &PrimitiveType) -> Option { + match (self, other) { + (PrimitiveType::Void, _) => None, + (_, PrimitiveType::Void) => None, + + (PrimitiveType::Integer(i1), PrimitiveType::Integer(i2)) => { + Some(PrimitiveType::Integer(i1.common_type(i2))) + } + (PrimitiveType::Integer(_), PrimitiveType::Float(f)) => Some(PrimitiveType::Float(*f)), + (PrimitiveType::Integer(_), _) => None, + + (PrimitiveType::Float(f), PrimitiveType::Integer(_)) => Some(PrimitiveType::Float(*f)), + (PrimitiveType::Float(f1), PrimitiveType::Float(f2)) => { + Some(PrimitiveType::Float(f1.common_type(f2))) + } + (PrimitiveType::Float(_), _) => None, + + (PrimitiveType::Struct(s1), PrimitiveType::Struct(s2)) => { + if s1 == s2 { + Some(PrimitiveType::Struct(s1.clone())) + } else { + None + } + } + (PrimitiveType::Struct(_), _) => None, + + (PrimitiveType::Union(s1), PrimitiveType::Union(s2)) => { + if s1 == s2 { + Some(PrimitiveType::Union(s1.clone())) + } else { + None + } + } + (PrimitiveType::Union(_), _) => None, + + (PrimitiveType::Enum(e1), PrimitiveType::Enum(e2)) => { + if e1 == e2 { + Some(PrimitiveType::Enum(e1.clone())) + } else { + None + } + } + (PrimitiveType::Enum(_), _) => None, + + (PrimitiveType::Pointer(p1), PrimitiveType::Pointer(p2)) => { + if p1 == p2 { + Some(PrimitiveType::Pointer(p1.clone())) + } else { + None + } + } + (PrimitiveType::Pointer(_), _) => None, + + (PrimitiveType::Array(a1), PrimitiveType::Array(a2)) => a1 + .clone() + .to_pointer() + .common_type(&a2.clone().to_pointer()), + (PrimitiveType::Array(_), _) => None, + + (PrimitiveType::Function(f1), PrimitiveType::Function(f2)) => { + if f1 == f2 { + Some(PrimitiveType::Function(f1.clone())) + } else { + None + } + } + (PrimitiveType::Function(_), _) => None, } } } @@ -360,6 +245,11 @@ pub struct ArrayType { pub cv_type: Box, pub size: usize, } +impl ArrayType { + pub fn to_pointer(self) -> PrimitiveType { + PrimitiveType::Pointer(self.cv_type) + } +} #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct FunctionType { // maybe no need CV qualifier for return type? @@ -476,7 +366,7 @@ impl EnumType { EnumType { name, body: Some(EnumBody { members }), - type_: Box::new(PrimitiveType::Int64), + type_: Box::new(PrimitiveType::Integer(Integer::Int64)), } } } diff --git a/src/virtualmachine/generator.rs b/src/virtualmachine/generator.rs index ea7fe23..976cc57 100644 --- a/src/virtualmachine/generator.rs +++ b/src/virtualmachine/generator.rs @@ -68,7 +68,7 @@ impl InstructionGenerator { pub fn emit_statement(&mut self, statement: Statement) -> Result<(), CompileError> { match statement { - Statement::None => {} + Statement::None => Ok(()), Statement::Expression(stmt) => self.emit_statement_expression(stmt), Statement::Labeled(stmt) => self.emit_statement_labeled(stmt), Statement::Goto(stmt) => self.emit_statement_goto(stmt), @@ -87,7 +87,6 @@ impl InstructionGenerator { Statement::DoWhile(stmt) => self.emit_statement_dowhile(stmt), Statement::VariableDeclaration(stmt) => self.emit_statement_variable_declaration(stmt), } - Ok(()) } pub fn emit_expression(&mut self, expression: Expression) -> Result<(), CompileError> { @@ -114,101 +113,112 @@ impl InstructionGenerator { Expression::Binary(expr) => self.emit_expression_binary(expr), Expression::InitializerList(expr) => self.emit_expression_initializerlist(expr), } + } + pub fn emit_expression_derefed(&mut self, expression: Expression) -> Result<(), CompileError> { + let size = expression.cv_type()?.type_.sizeof()?; + if expression.is_address() { + self.emit_expression(expression)?; + self.instructions.push(Instruction::Deref(size)); + } else { + self.emit_expression(expression)?; + } Ok(()) } } impl InstructionGenerator { - fn emit_statement_expression(&mut self, stmt: ast2::StmtExpression) {} - fn emit_statement_labeled(&mut self, stmt: ast2::StmtLabeled) {} - fn emit_statement_goto(&mut self, stmt: ast2::StmtGoto) {} - fn emit_statement_compound(&mut self, stmt: ast2::StmtCompound) {} - fn emit_statement_if(&mut self, stmt: ast2::StmtIf) {} - fn emit_statement_switch(&mut self, stmt: ast2::StmtSwitch) {} - fn emit_statement_continue(&mut self) {} - fn emit_statement_break(&mut self) {} - fn emit_statement_return(&mut self, stmt: ast2::StmtReturn) {} - fn emit_statement_for(&mut self, stmt: ast2::StmtFor) {} - fn emit_statement_while(&mut self, stmt: ast2::StmtWhile) {} - fn emit_statement_dowhile(&mut self, stmt: ast2::StmtDoWhile) {} - fn emit_statement_variable_declaration(&mut self, stmt: ast2::StmtVariableDeclaration) {} + fn emit_statement_expression( + &mut self, + stmt: ast2::StmtExpression, + ) -> Result<(), CompileError> { + self.emit_expression(*stmt.expr) + } + fn emit_statement_labeled(&mut self, stmt: ast2::StmtLabeled) -> Result<(), CompileError> {} + fn emit_statement_goto(&mut self, stmt: ast2::StmtGoto) -> Result<(), CompileError> {} + fn emit_statement_compound(&mut self, stmt: ast2::StmtCompound) -> Result<(), CompileError> {} + fn emit_statement_if(&mut self, stmt: ast2::StmtIf) -> Result<(), CompileError> {} + fn emit_statement_switch(&mut self, stmt: ast2::StmtSwitch) -> Result<(), CompileError> {} + fn emit_statement_continue(&mut self) -> Result<(), CompileError> {} + fn emit_statement_break(&mut self) -> Result<(), CompileError> {} + fn emit_statement_return(&mut self, stmt: ast2::StmtReturn) -> Result<(), CompileError> {} + fn emit_statement_for(&mut self, stmt: ast2::StmtFor) -> Result<(), CompileError> {} + fn emit_statement_while(&mut self, stmt: ast2::StmtWhile) -> Result<(), CompileError> {} + fn emit_statement_dowhile(&mut self, stmt: ast2::StmtDoWhile) -> Result<(), CompileError> {} + fn emit_statement_variable_declaration( + &mut self, + stmt: ast2::StmtVariableDeclaration, + ) -> Result<(), CompileError> { + } } impl InstructionGenerator { - fn emit_expression_i8(&mut self, expr: i8) { + fn emit_expression_i8(&mut self, expr: i8) -> Result<(), CompileError> { self.instructions.push(Instruction::I64(expr as i64)); + Ok(()) } - fn emit_expression_i16(&mut self, expr: i16) { + fn emit_expression_i16(&mut self, expr: i16) -> Result<(), CompileError> { self.instructions.push(Instruction::I64(expr as i64)); + Ok(()) } - fn emit_expression_i32(&mut self, expr: i32) { + fn emit_expression_i32(&mut self, expr: i32) -> Result<(), CompileError> { self.instructions.push(Instruction::I64(expr as i64)); + Ok(()) } - fn emit_expression_i64(&mut self, expr: i64) { + fn emit_expression_i64(&mut self, expr: i64) -> Result<(), CompileError> { self.instructions.push(Instruction::I64(expr)); + Ok(()) } - fn emit_expression_u8(&mut self, expr: u8) { + fn emit_expression_u8(&mut self, expr: u8) -> Result<(), CompileError> { self.instructions.push(Instruction::U64(expr as u64)); + Ok(()) } - fn emit_expression_u16(&mut self, expr: u16) { + fn emit_expression_u16(&mut self, expr: u16) -> Result<(), CompileError> { self.instructions.push(Instruction::U64(expr as u64)); + Ok(()) } - fn emit_expression_u32(&mut self, expr: u32) { + fn emit_expression_u32(&mut self, expr: u32) -> Result<(), CompileError> { self.instructions.push(Instruction::U64(expr as u64)); + Ok(()) } - fn emit_expression_u64(&mut self, expr: u64) { + fn emit_expression_u64(&mut self, expr: u64) -> Result<(), CompileError> { self.instructions.push(Instruction::U64(expr)); + Ok(()) } - fn emit_expression_f32(&mut self, expr: f32) { + fn emit_expression_f32(&mut self, expr: f32) -> Result<(), CompileError> { let bits = expr.to_bits(); self.instructions.push(Instruction::U64(bits as u64)); + Ok(()) } - fn emit_expression_f64(&mut self, expr: f64) { + fn emit_expression_f64(&mut self, expr: f64) -> Result<(), CompileError> { let bits = expr.to_bits(); self.instructions.push(Instruction::U64(bits)); + Ok(()) } - fn emit_expression_string(&mut self, expr: String) { + fn emit_expression_string(&mut self, expr: String) -> Result<(), CompileError> { unimplemented!("emit_expression_string"); } - fn emit_expression_variable(&mut self, expr: VariableInfo) { + fn emit_expression_variable(&mut self, expr: VariableInfo) -> Result<(), CompileError> { self.instructions .push(Instruction::U64(expr.address.into_u64())); + Ok(()) } - fn emit_expression_conditional(&mut self, expr: ast2::ExprConditional) { + fn emit_expression_conditional( + &mut self, + expr: ast2::ExprConditional, + ) -> Result<(), CompileError> { let else_label = self.generate_label(); let end_label = self.generate_label(); + let cond_size = expr.cond.cv_type()?.type_.sizeof()?; - if self.cond.is_return_reference(instructions) { - self.emit_expression(*expr.cond); - - instructions.push(Instruction::JumpZero(JumpZero { - label: else_label.clone(), - operand_cond: Operand::Derefed(0, 0), - })); - } else { - self.emit_expression(*expr.cond); - - instructions.push(Instruction::JumpZero(JumpZero { - label: else_label.clone(), - operand_cond: Operand::Register(0), - })); - } + self.emit_expression_derefed(*expr.cond)?; + self.instructions + .push(Instruction::JumpZero(cond_size, else_label)); - self.then_expr.emit(instructions); - if self.then_expr.is_return_reference(instructions) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(0, 0), - operand_to: Operand::Register(1), - })); - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Register(1), - operand_to: Operand::Register(0), - })); - } - instructions.push(Instruction::Jump(Jump { - label: end_label.clone(), - })); - instructions.set_label(&else_label); + let then_size = expr.then_expr.cv_type()?.type_.sizeof()?; + self.emit_expression_derefed(*expr.then_expr)?; + self.instructions.push(Instruction::Jump(end_label)); + self.set_label(else_label); + self.emit_expression_derefed(*expr.else_expr)?; self.else_expr.emit(instructions); if self.else_expr.is_return_reference(instructions) { instructions.push(Instruction::MoveRegister(MoveRegister { @@ -222,12 +232,16 @@ impl InstructionGenerator { } instructions.set_label(&end_label); } - fn emit_expression_cast(&mut self, expr: ast2::ExprCast) {} - fn emit_expression_member(&mut self, expr: ast2::ExprMember) {} - fn emit_expression_arrow(&mut self, expr: ast2::ExprMember) {} - fn emit_expression_paren(&mut self, expr: ast2::ExprParen) {} - fn emit_expression_bracket(&mut self, expr: ast2::ExprBracket) {} - fn emit_expression_unary(&mut self, expr: ast2::ExprUnary) {} - fn emit_expression_binary(&mut self, expr: ast2::ExprBinary) {} - fn emit_expression_initializerlist(&mut self, expr: ast2::ExprInitializerList) {} + fn emit_expression_cast(&mut self, expr: ast2::ExprCast) -> Result<(), CompileError> {} + fn emit_expression_member(&mut self, expr: ast2::ExprMember) -> Result<(), CompileError> {} + fn emit_expression_arrow(&mut self, expr: ast2::ExprMember) -> Result<(), CompileError> {} + fn emit_expression_paren(&mut self, expr: ast2::ExprParen) -> Result<(), CompileError> {} + fn emit_expression_bracket(&mut self, expr: ast2::ExprBracket) -> Result<(), CompileError> {} + fn emit_expression_unary(&mut self, expr: ast2::ExprUnary) -> Result<(), CompileError> {} + fn emit_expression_binary(&mut self, expr: ast2::ExprBinary) -> Result<(), CompileError> {} + fn emit_expression_initializerlist( + &mut self, + expr: ast2::ExprInitializerList, + ) -> Result<(), CompileError> { + } } diff --git a/src/virtualmachine/instruction.rs b/src/virtualmachine/instruction.rs index 704a8f9..0e82928 100644 --- a/src/virtualmachine/instruction.rs +++ b/src/virtualmachine/instruction.rs @@ -1,15 +1,21 @@ -use super::vm::{STACK_POINTER_BASE_REGISTER, STACK_POINTER_REGISTER, STACK_SIZE}; +use super::LabelType; #[derive(Debug, Clone)] pub enum Instruction { I64(i64), U64(u64), + /// Dereference N bytes from the address in register RAX. + /// Put the value in register RAX. + Deref(usize), + + Jump(LabelType), + JumpZero(usize, LabelType), + MoveRegister(MoveRegister), PushStack(PushStack), PopStack(PopStack), Jump(Jump), - JumpZero(JumpZero), JumpNonZero(JumpNonZero), Print(Print), Panic(Panic), From 7eecad48e9364d2bc6db74b730ee32597fa89a29 Mon Sep 17 00:00:00 2001 From: ehwan Date: Fri, 8 Nov 2024 11:48:04 +0900 Subject: [PATCH 10/10] implemented IR generation for almost all statements and expressions --- src/ast2/context.rs | 2181 ++++++++++++++++++++++++++--- src/ast2/error.rs | 7 +- src/ast2/expression.rs | 206 ++- src/ast2/statement.rs | 2 + src/ast2/typename.rs | 48 +- src/ast2/variable.rs | 34 +- src/main.rs | 24 +- src/virtualmachine/generator.rs | 1477 +++++++++++++++++-- src/virtualmachine/instruction.rs | 1781 +---------------------- src/virtualmachine/mod.rs | 5 +- src/virtualmachine/operand.rs | 68 +- src/virtualmachine/vm.rs | 1005 ++++++++++++- 12 files changed, 4630 insertions(+), 2208 deletions(-) diff --git a/src/ast2/context.rs b/src/ast2/context.rs index b252466..bd5ffc0 100644 --- a/src/ast2/context.rs +++ b/src/ast2/context.rs @@ -11,8 +11,8 @@ use super::CVType; use super::CombinedDeclarator; use super::CompileError; use super::EnumType; -use super::ExprBinary; use super::ExprBinaryOp; +use super::ExprCast; use super::ExprUnaryOp; use super::Expression; use super::Float; @@ -45,6 +45,9 @@ pub struct Context { pub global_scope: GlobalScope, pub function_scope: Option, pub scopes: Vec, + + /// constant text section + pub text: Vec, } impl Context { @@ -54,6 +57,7 @@ impl Context { global_scope: GlobalScope::new(), function_scope: None, scopes: Vec::new(), + text: Vec::new(), } } @@ -240,7 +244,10 @@ impl Context { statements.push(statement); } - Ok(TranslationUnit { statements }) + Ok(TranslationUnit { + statements, + text: std::mem::take(&mut self.text), + }) } pub fn process_statement( &mut self, @@ -405,6 +412,11 @@ impl Context { stmt: ast::StmtIf, ) -> Result { let cond = self.process_expression(stmt.cond)?; + match cond.cv_type()?.type_ { + PrimitiveType::Integer(_) => {} + PrimitiveType::Pointer(_) => {} + type_ => return Err(CompileError::InvalidIfCondition(type_)), + } let then = self.process_statement(*stmt.then_statement)?; let else_ = if let Some(stmt) = stmt.else_statement { Some(Box::new(self.process_statement(*stmt)?)) @@ -432,7 +444,8 @@ impl Context { }; let mut cases: Vec = Vec::new(); - for s in body.statements.into_iter() { + let mut default = None; + for (idx, s) in body.statements.into_iter().enumerate() { match s { Statement::_Case(c) => { cases.push(StmtSwitchCase { @@ -441,6 +454,7 @@ impl Context { }); } Statement::_Default(d) => { + default = Some(idx); cases.push(StmtSwitchCase { value: None, statements: vec![*d.statement], @@ -455,12 +469,17 @@ impl Context { } } } - Ok(Statement::Switch(statement::StmtSwitch { value, cases })) + Ok(Statement::Switch(statement::StmtSwitch { + value, + cases, + default, + })) } pub(crate) fn process_statement_case( &mut self, stmt: ast::StmtCase, ) -> Result { + // @TODO comparable check let value = self.process_expression(stmt.value)?; let statement = self.process_statement(*stmt.statement)?; if self.nearest_switch_scope().is_none() { @@ -517,6 +536,9 @@ impl Context { let cond = self.process_expression(stmt.cond)?; let body = self.process_statement(*stmt.statement)?; + if !cond.cv_type()?.type_.is_bool_castable() { + return Err(CompileError::ConditionalNotBool); + } self.end_loop_scope()?; @@ -533,6 +555,9 @@ impl Context { let body = self.process_statement(*stmt.statement)?; let cond = self.process_expression(stmt.cond)?; + if !cond.cv_type()?.type_.is_bool_castable() { + return Err(CompileError::ConditionalNotBool); + } self.end_loop_scope()?; @@ -549,6 +574,9 @@ impl Context { let init = self.process_statement(*stmt.init)?; let cond = self.process_expression(stmt.cond)?; + if !cond.cv_type()?.type_.is_bool_castable() { + return Err(CompileError::ConditionalNotBool); + } let next = if let Some(expr) = stmt.next { Some(self.process_expression(expr)?) } else { @@ -634,7 +662,26 @@ impl Context { )?; if let Some(init) = init.initializer { let init = self.process_expression(init)?; - pairs.push((varinfo, init)); + let rhs_type = init.cv_type()?.type_; + if !rhs_type.is_implicitly_castable(&varinfo.cv_type.type_) { + return Err(CompileError::InitializeTypeMismatch( + varinfo.cv_type.type_, + init.cv_type()?.type_, + )); + } + if rhs_type != varinfo.cv_type.type_ { + // implicit cast + let lhs_type = varinfo.cv_type.type_.clone(); + pairs.push(( + varinfo, + Expression::Cast(ExprCast { + type_: lhs_type, + expr: Box::new(init), + }), + )); + } else { + pairs.push((varinfo, init)); + } } } else { if self.global_scope.variables.contains_key(&name) { @@ -652,7 +699,26 @@ impl Context { self.global_scope.variables.insert(name, varinfo.clone()); if let Some(init) = init.initializer { let init = self.process_expression(init)?; - pairs.push((varinfo, init)); + let rhs_type = init.cv_type()?.type_; + if !rhs_type.is_implicitly_castable(&varinfo.cv_type.type_) { + return Err(CompileError::InitializeTypeMismatch( + varinfo.cv_type.type_, + init.cv_type()?.type_, + )); + } + if rhs_type != varinfo.cv_type.type_ { + // implicit cast + let lhs_type = varinfo.cv_type.type_.clone(); + pairs.push(( + varinfo, + Expression::Cast(ExprCast { + type_: lhs_type, + expr: Box::new(init), + }), + )); + } else { + pairs.push((varinfo, init)); + } } else { // @TODO // default value since this variable is in static storage @@ -1214,7 +1280,11 @@ impl Context { &mut self, expr: ast::ExprString, ) -> Result { - Ok(Expression::String(expr.value)) + let addr = self.text.len(); + self.text.reserve(expr.value.len() + 1); + self.text.extend_from_slice(expr.value.as_bytes()); + self.text.push(0u8); + Ok(Expression::String(Address::Text(addr))) } pub(crate) fn process_expression_cast( &mut self, @@ -1457,7 +1527,10 @@ impl Context { } } ExprUnaryOp::DecrementPost => { - if !matches!(src_type.type_, PrimitiveType::Integer(_)) { + if !matches!( + src_type.type_, + PrimitiveType::Integer(_) | PrimitiveType::Pointer(_) + ) { return Err(CompileError::BitwiseOpOnNonInteger); } if src_type.const_ { @@ -1468,7 +1541,10 @@ impl Context { } } ExprUnaryOp::DecrementPre => { - if !matches!(src_type.type_, PrimitiveType::Integer(_)) { + if !matches!( + src_type.type_, + PrimitiveType::Integer(_) | PrimitiveType::Pointer(_) + ) { return Err(CompileError::BitwiseOpOnNonInteger); } if src_type.const_ { @@ -1479,7 +1555,10 @@ impl Context { } } ExprUnaryOp::IncrementPost => { - if !matches!(src_type.type_, PrimitiveType::Integer(_)) { + if !matches!( + src_type.type_, + PrimitiveType::Integer(_) | PrimitiveType::Pointer(_) + ) { return Err(CompileError::BitwiseOpOnNonInteger); } if src_type.const_ { @@ -1490,7 +1569,10 @@ impl Context { } } ExprUnaryOp::IncrementPre => { - if !matches!(src_type.type_, PrimitiveType::Integer(_)) { + if !matches!( + src_type.type_, + PrimitiveType::Integer(_) | PrimitiveType::Pointer(_) + ) { return Err(CompileError::BitwiseOpOnNonInteger); } if src_type.const_ { @@ -1572,132 +1654,1014 @@ impl Context { match expr.op { ExprBinaryOp::Add => match (lhs_type, rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} - (PrimitiveType::Integer(_), PrimitiveType::Pointer(_)) => {} - (PrimitiveType::Integer(_), PrimitiveType::Array(_)) => {} + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + let common_type = a.common_type(&b); + let lhs = if a != common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Integer(common_type.clone()), + }) + } else { + lhs + }; - (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + let rhs = if b != common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(common_type.clone()), + }) + } else { + rhs + }; - (PrimitiveType::Pointer(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Array(_), PrimitiveType::Integer(_)) => {} + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Integer(_), PrimitiveType::Float(f)) => { + let lhs = Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Float(f), + }); + + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Integer(a), PrimitiveType::Pointer(p)) => { + let sizeof = p.sizeof()? as u64; + + let rhs = Expression::Cast(expression::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(Integer::UInt64), + }); + + let lhs = if a.sizeof() != 64 { + if a.is_signed() { + let lhs = Expression::Cast(expression::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Integer(Integer::Int64), + }); + + let lhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(lhs), + rhs: Box::new(Expression::Signed(sizeof as i64, Integer::Int64)), + }); + lhs + } else { + let lhs = Expression::Cast(expression::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Integer(Integer::UInt64), + }); + let lhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(lhs), + rhs: Box::new(Expression::Unsigned(sizeof, Integer::UInt64)), + }); + lhs + } + } else { + if a.is_signed() { + let lhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(lhs), + rhs: Box::new(Expression::Signed(sizeof as i64, Integer::Int64)), + }); + lhs + } else { + let lhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(lhs), + rhs: Box::new(Expression::Unsigned(sizeof, Integer::UInt64)), + }); + lhs + } + }; + + return Ok(Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Add, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Integer(a), PrimitiveType::Array(p)) => { + let sizeof = p.cv_type.sizeof()? as u64; + + let rhs = Expression::Cast(expression::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(Integer::UInt64), + }); + + let lhs = if a.sizeof() != 64 { + if a.is_signed() { + let lhs = Expression::Cast(expression::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Integer(Integer::Int64), + }); + + let lhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(lhs), + rhs: Box::new(Expression::Signed(sizeof as i64, Integer::Int64)), + }); + lhs + } else { + let lhs = Expression::Cast(expression::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Integer(Integer::UInt64), + }); + let lhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(lhs), + rhs: Box::new(Expression::Unsigned(sizeof, Integer::UInt64)), + }); + lhs + } + } else { + if a.is_signed() { + let lhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(lhs), + rhs: Box::new(Expression::Signed(sizeof as i64, Integer::Int64)), + }); + lhs + } else { + let lhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(lhs), + rhs: Box::new(Expression::Unsigned(sizeof, Integer::UInt64)), + }); + lhs + } + }; + + return Ok(Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Add, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + + (PrimitiveType::Float(f), PrimitiveType::Integer(_)) => { + let rhs = Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Float(f), + }); + + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Float(a), PrimitiveType::Float(b)) => { + let common_type = a.common_type(&b); + let lhs = if a != common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Float(common_type.clone()), + }) + } else { + lhs + }; + + let rhs = if b != common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Float(common_type.clone()), + }) + } else { + rhs + }; + + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + + (PrimitiveType::Pointer(p), PrimitiveType::Integer(b)) => { + let sizeof = p.sizeof()? as u64; + + let lhs = Expression::Cast(expression::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Integer(Integer::UInt64), + }); + + let rhs = if b.sizeof() != 64 { + if b.is_signed() { + let rhs = Expression::Cast(expression::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(Integer::Int64), + }); + + let rhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(rhs), + rhs: Box::new(Expression::Signed(sizeof as i64, Integer::Int64)), + }); + rhs + } else { + let rhs = Expression::Cast(expression::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(Integer::UInt64), + }); + let rhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(rhs), + rhs: Box::new(Expression::Unsigned(sizeof, Integer::UInt64)), + }); + rhs + } + } else { + if b.is_signed() { + let rhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(rhs), + rhs: Box::new(Expression::Signed(sizeof as i64, Integer::Int64)), + }); + rhs + } else { + let rhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(rhs), + rhs: Box::new(Expression::Unsigned(sizeof, Integer::UInt64)), + }); + rhs + } + }; + + return Ok(Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Add, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Array(p), PrimitiveType::Integer(b)) => { + let sizeof = p.cv_type.sizeof()? as u64; + + let lhs = Expression::Cast(expression::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Integer(Integer::UInt64), + }); + + let rhs = if b.sizeof() != 64 { + if b.is_signed() { + let rhs = Expression::Cast(expression::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(Integer::Int64), + }); + + let rhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(rhs), + rhs: Box::new(Expression::Signed(sizeof as i64, Integer::Int64)), + }); + rhs + } else { + let rhs = Expression::Cast(expression::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(Integer::UInt64), + }); + let rhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(rhs), + rhs: Box::new(Expression::Unsigned(sizeof, Integer::UInt64)), + }); + rhs + } + } else { + if b.is_signed() { + let rhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(rhs), + rhs: Box::new(Expression::Signed(sizeof as i64, Integer::Int64)), + }); + rhs + } else { + let rhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(rhs), + rhs: Box::new(Expression::Unsigned(sizeof, Integer::UInt64)), + }); + rhs + } + }; + + return Ok(Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Add, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } _ => return Err(CompileError::ArithmeticOpOnNonNumeric), }, - ExprBinaryOp::AddAssign => { - if !lhs.is_address() { - return Err(CompileError::NotAssignable); + ExprBinaryOp::Sub => match (lhs_type, rhs_type) { + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + let common_type = a.common_type(&b); + let lhs = if a != common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Integer(common_type.clone()), + }) + } else { + lhs + }; + + let rhs = if b != common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(common_type.clone()), + }) + } else { + rhs + }; + + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); } - if lhs.cv_type()?.const_ { - return Err(CompileError::AssignToConst); + (PrimitiveType::Integer(_), PrimitiveType::Float(f)) => { + let lhs = Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Float(f), + }); + + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); } - match (lhs_type, rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} - (PrimitiveType::Integer(_), PrimitiveType::Pointer(_)) => {} - (PrimitiveType::Integer(_), PrimitiveType::Array(_)) => {} - (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + (PrimitiveType::Float(f), PrimitiveType::Integer(_)) => { + let rhs = Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Float(f), + }); + + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Float(a), PrimitiveType::Float(b)) => { + let common_type = a.common_type(&b); + let lhs = if a != common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Float(common_type.clone()), + }) + } else { + lhs + }; - (PrimitiveType::Pointer(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Array(_), PrimitiveType::Integer(_)) => {} + let rhs = if b != common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Float(common_type.clone()), + }) + } else { + rhs + }; - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); } - } - ExprBinaryOp::Sub => match (lhs_type, rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} - (PrimitiveType::Integer(_), PrimitiveType::Pointer(_)) => {} - (PrimitiveType::Integer(_), PrimitiveType::Array(_)) => {} - (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + (PrimitiveType::Pointer(p), PrimitiveType::Integer(b)) => { + let sizeof = p.sizeof()? as u64; + + let lhs = Expression::Cast(expression::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Integer(Integer::UInt64), + }); - (PrimitiveType::Pointer(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Array(_), PrimitiveType::Integer(_)) => {} + let rhs = if b.sizeof() != 64 { + if b.is_signed() { + let rhs = Expression::Cast(expression::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(Integer::Int64), + }); + + let rhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(rhs), + rhs: Box::new(Expression::Signed(sizeof as i64, Integer::Int64)), + }); + rhs + } else { + let rhs = Expression::Cast(expression::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(Integer::UInt64), + }); + let rhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(rhs), + rhs: Box::new(Expression::Unsigned(sizeof, Integer::UInt64)), + }); + rhs + } + } else { + if b.is_signed() { + let rhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(rhs), + rhs: Box::new(Expression::Signed(sizeof as i64, Integer::Int64)), + }); + rhs + } else { + let rhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(rhs), + rhs: Box::new(Expression::Unsigned(sizeof, Integer::UInt64)), + }); + rhs + } + }; + + return Ok(Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Sub, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Array(p), PrimitiveType::Integer(b)) => { + let sizeof = p.cv_type.sizeof()? as u64; + + let lhs = Expression::Cast(expression::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Integer(Integer::UInt64), + }); + + let rhs = if b.sizeof() != 64 { + if b.is_signed() { + let rhs = Expression::Cast(expression::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(Integer::Int64), + }); + + let rhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(rhs), + rhs: Box::new(Expression::Signed(sizeof as i64, Integer::Int64)), + }); + rhs + } else { + let rhs = Expression::Cast(expression::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(Integer::UInt64), + }); + let rhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(rhs), + rhs: Box::new(Expression::Unsigned(sizeof, Integer::UInt64)), + }); + rhs + } + } else { + if b.is_signed() { + let rhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(rhs), + rhs: Box::new(Expression::Signed(sizeof as i64, Integer::Int64)), + }); + rhs + } else { + let rhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(rhs), + rhs: Box::new(Expression::Unsigned(sizeof, Integer::UInt64)), + }); + rhs + } + }; + + return Ok(Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Sub, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } _ => return Err(CompileError::ArithmeticOpOnNonNumeric), }, - ExprBinaryOp::SubAssign => { + ExprBinaryOp::AddAssign => { if !lhs.is_address() { return Err(CompileError::NotAssignable); } if lhs.cv_type()?.const_ { return Err(CompileError::AssignToConst); } - match (lhs_type, rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} - (PrimitiveType::Integer(_), PrimitiveType::Pointer(_)) => {} - (PrimitiveType::Integer(_), PrimitiveType::Array(_)) => {} + let lhs_cloned = lhs.clone(); + let binary_op = match (lhs_type, rhs_type) { + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + let common_type = a.common_type(&b); + let lhs = if a != common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Integer(common_type.clone()), + }) + } else { + lhs + }; + + let rhs = if b != common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(common_type.clone()), + }) + } else { + rhs + }; + + Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + }) + } + (PrimitiveType::Integer(_), PrimitiveType::Float(f)) => { + let lhs = Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Float(f), + }); + + Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + }) + } + + (PrimitiveType::Float(f), PrimitiveType::Integer(_)) => { + let rhs = Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Float(f), + }); + + Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + }) + } + (PrimitiveType::Float(a), PrimitiveType::Float(b)) => { + let common_type = a.common_type(&b); + let lhs = if a != common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Float(common_type.clone()), + }) + } else { + lhs + }; + + let rhs = if b != common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Float(common_type.clone()), + }) + } else { + rhs + }; + + Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + }) + } - (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + (PrimitiveType::Pointer(p), PrimitiveType::Integer(b)) => { + let sizeof = p.sizeof()? as u64; + + let lhs = Expression::Cast(expression::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Integer(Integer::UInt64), + }); + + let rhs = if b.sizeof() != 64 { + if b.is_signed() { + let rhs = Expression::Cast(expression::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(Integer::Int64), + }); + + let rhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(rhs), + rhs: Box::new(Expression::Signed( + sizeof as i64, + Integer::Int64, + )), + }); + rhs + } else { + let rhs = Expression::Cast(expression::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(Integer::UInt64), + }); + let rhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(rhs), + rhs: Box::new(Expression::Unsigned(sizeof, Integer::UInt64)), + }); + rhs + } + } else { + if b.is_signed() { + let rhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(rhs), + rhs: Box::new(Expression::Signed( + sizeof as i64, + Integer::Int64, + )), + }); + rhs + } else { + let rhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(rhs), + rhs: Box::new(Expression::Unsigned(sizeof, Integer::UInt64)), + }); + rhs + } + }; - (PrimitiveType::Pointer(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Array(_), PrimitiveType::Integer(_)) => {} + Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Add, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + }) + } _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } - } - ExprBinaryOp::Mul => match (lhs_type, rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} + }; - (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + let rhs = if lhs_cloned.cv_type()?.type_ != binary_op.cv_type()?.type_ { + Expression::Cast(super::ExprCast { + expr: Box::new(binary_op), + type_: lhs_cloned.cv_type()?.type_.clone(), + }) + } else { + binary_op + }; - _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - }, - ExprBinaryOp::MulAssign => { + let assign_op = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Assign, + lhs: Box::new(lhs_cloned), + rhs: Box::new(rhs), + }); + return Ok(assign_op); + } + ExprBinaryOp::SubAssign => { if !lhs.is_address() { return Err(CompileError::NotAssignable); } if lhs.cv_type()?.const_ { return Err(CompileError::AssignToConst); } - match (lhs_type, rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} + let lhs_cloned = lhs.clone(); + let binary_op = match (lhs_type, rhs_type) { + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + let common_type = a.common_type(&b); + let lhs = if a != common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Integer(common_type.clone()), + }) + } else { + lhs + }; + + let rhs = if b != common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(common_type.clone()), + }) + } else { + rhs + }; + + Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + }) + } + (PrimitiveType::Integer(_), PrimitiveType::Float(f)) => { + let lhs = Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Float(f), + }); + + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } - (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + (PrimitiveType::Float(f), PrimitiveType::Integer(_)) => { + let rhs = Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Float(f), + }); + + Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + }) + } + (PrimitiveType::Float(a), PrimitiveType::Float(b)) => { + let common_type = a.common_type(&b); + let lhs = if a != common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Float(common_type.clone()), + }) + } else { + lhs + }; + + let rhs = if b != common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Float(common_type.clone()), + }) + } else { + rhs + }; + + Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + }) + } + + (PrimitiveType::Pointer(p), PrimitiveType::Integer(b)) => { + let sizeof = p.sizeof()? as u64; + + let lhs = Expression::Cast(expression::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Integer(Integer::UInt64), + }); + + let rhs = if b.sizeof() != 64 { + if b.is_signed() { + let rhs = Expression::Cast(expression::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(Integer::Int64), + }); + + let rhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(rhs), + rhs: Box::new(Expression::Signed( + sizeof as i64, + Integer::Int64, + )), + }); + rhs + } else { + let rhs = Expression::Cast(expression::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(Integer::UInt64), + }); + let rhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(rhs), + rhs: Box::new(Expression::Unsigned(sizeof, Integer::UInt64)), + }); + rhs + } + } else { + if b.is_signed() { + let rhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(rhs), + rhs: Box::new(Expression::Signed( + sizeof as i64, + Integer::Int64, + )), + }); + rhs + } else { + let rhs = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mul, + lhs: Box::new(rhs), + rhs: Box::new(Expression::Unsigned(sizeof, Integer::UInt64)), + }); + rhs + } + }; + + Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Sub, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + }) + } _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } + }; + + let rhs = if lhs_cloned.cv_type()?.type_ != binary_op.cv_type()?.type_ { + Expression::Cast(super::ExprCast { + expr: Box::new(binary_op), + type_: lhs_cloned.cv_type()?.type_.clone(), + }) + } else { + binary_op + }; + + let assign_op = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Assign, + lhs: Box::new(lhs_cloned), + rhs: Box::new(rhs), + }); + return Ok(assign_op); } - ExprBinaryOp::Div => match (lhs_type, rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} + ExprBinaryOp::Mul | ExprBinaryOp::Div => match (lhs_type, rhs_type) { + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + let common_type = a.common_type(&b); + + let lhs = if a != common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Integer(common_type.clone()), + }) + } else { + lhs + }; + let rhs = if b != common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(common_type.clone()), + }) + } else { + rhs + }; + + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Integer(_), PrimitiveType::Float(b)) => { + let lhs = Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Float(b), + }); + + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + + (PrimitiveType::Float(a), PrimitiveType::Integer(_)) => { + let rhs = Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Float(a), + }); + + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Float(a), PrimitiveType::Float(b)) => { + let common_type = a.common_type(&b); + + let lhs = if a != common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Float(common_type.clone()), + }) + } else { + lhs + }; + let rhs = if b != common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Float(common_type.clone()), + }) + } else { + rhs + }; - (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } _ => return Err(CompileError::ArithmeticOpOnNonNumeric), }, - ExprBinaryOp::DivAssign => { + ExprBinaryOp::MulAssign | ExprBinaryOp::DivAssign => { if !lhs.is_address() { return Err(CompileError::NotAssignable); } if lhs.cv_type()?.const_ { return Err(CompileError::AssignToConst); } - match (lhs_type, rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} + let common_type = match (&lhs_type, &rhs_type) { + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + PrimitiveType::Integer(a.common_type(&b)) + } + (PrimitiveType::Integer(_), PrimitiveType::Float(f)) => { + PrimitiveType::Float(*f) + } - (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + (PrimitiveType::Float(f), PrimitiveType::Integer(_)) => { + PrimitiveType::Float(*f) + } + (PrimitiveType::Float(a), PrimitiveType::Float(b)) => { + PrimitiveType::Float(a.common_type(&b)) + } _ => return Err(CompileError::ArithmeticOpOnNonNumeric), - } + }; + + let lhs_casted = if lhs_type != common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(lhs.clone()), + type_: common_type.clone(), + }) + } else { + lhs.clone() + }; + let rhs = if rhs_type != common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: common_type.clone(), + }) + } else { + rhs + }; + + let op = Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs_casted), + rhs: Box::new(rhs), + }); + let assign_op = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Assign, + lhs: Box::new(lhs), + rhs: Box::new(op), + }); + return Ok(assign_op); } ExprBinaryOp::Mod => match (lhs_type, rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + let common_type = a.common_type(&b); + + let lhs = if a != common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Integer(common_type.clone()), + }) + } else { + lhs + }; + let rhs = if b != common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(common_type.clone()), + }) + } else { + rhs + }; + + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } _ => return Err(CompileError::ArithmeticOpOnNonNumeric), }, @@ -1709,53 +2673,137 @@ impl Context { return Err(CompileError::AssignToConst); } match (lhs_type, rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} - - (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + let common_type = a.common_type(&b); + + let rhs = if b != common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(common_type.clone()), + }) + } else { + rhs + }; + + if a != common_type { + let lhs_casted = Expression::Cast(super::ExprCast { + expr: Box::new(lhs.clone()), + type_: PrimitiveType::Integer(common_type.clone()), + }); + let mod_op = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mod, + lhs: Box::new(lhs_casted), + rhs: Box::new(rhs), + }); + let mod_op = Expression::Cast(super::ExprCast { + expr: Box::new(mod_op), + type_: PrimitiveType::Integer(a.clone()), + }); + let assign_op = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Assign, + lhs: Box::new(lhs), + rhs: Box::new(mod_op), + }); + + return Ok(assign_op); + } else { + let lhs_casted = lhs.clone(); + let mod_op = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Mod, + lhs: Box::new(lhs_casted), + rhs: Box::new(rhs), + }); + let assign_op = Expression::Binary(expression::ExprBinary { + op: ExprBinaryOp::Assign, + lhs: Box::new(lhs), + rhs: Box::new(mod_op), + }); + + return Ok(assign_op); + } + } _ => return Err(CompileError::ArithmeticOpOnNonNumeric), } } - ExprBinaryOp::BitwiseAnd => match (lhs_type, rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} - _ => return Err(CompileError::BitwiseOpOnNonInteger), - }, - ExprBinaryOp::BitwiseAndAssign => { - if !lhs.is_address() { - return Err(CompileError::NotAssignable); - } - if lhs.cv_type()?.const_ { - return Err(CompileError::AssignToConst); - } + ExprBinaryOp::BitwiseAnd | ExprBinaryOp::BitwiseOr | ExprBinaryOp::BitwiseXor => { match (lhs_type, rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + let common = a.common_type(&b); + let lhs = if a != common { + Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Integer(common.clone()), + }) + } else { + lhs + }; + let rhs = if b != common { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(common.clone()), + }) + } else { + rhs + }; + + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } _ => return Err(CompileError::BitwiseOpOnNonInteger), } } - ExprBinaryOp::BitwiseOr => match (lhs_type, rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} - _ => return Err(CompileError::BitwiseOpOnNonInteger), - }, - ExprBinaryOp::BitwiseOrAssign => { + ExprBinaryOp::BitwiseAndAssign + | ExprBinaryOp::BitwiseOrAssign + | ExprBinaryOp::BitwiseXorAssign => { if !lhs.is_address() { return Err(CompileError::NotAssignable); } if lhs.cv_type()?.const_ { return Err(CompileError::AssignToConst); } - match (lhs_type, rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + let rhs = if a != b { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(a.clone()), + }) + } else { + rhs + }; + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } _ => return Err(CompileError::BitwiseOpOnNonInteger), } } - ExprBinaryOp::BitwiseXor => match (lhs_type, rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + ExprBinaryOp::ShiftLeft | ExprBinaryOp::ShiftRight => match (lhs_type, rhs_type) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(b)) => { + let rhs = if b != Integer::UInt8 { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(Integer::UInt8), + }) + } else { + rhs + }; + + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } _ => return Err(CompileError::BitwiseOpOnNonInteger), }, - ExprBinaryOp::BitwiseXorAssign => { + ExprBinaryOp::ShiftLeftAssign | ExprBinaryOp::ShiftRightAssign => { if !lhs.is_address() { return Err(CompileError::NotAssignable); } @@ -1764,125 +2812,873 @@ impl Context { } match (lhs_type, rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} + (PrimitiveType::Integer(_), PrimitiveType::Integer(b)) => { + let rhs = if b != Integer::UInt8 { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(Integer::UInt8), + }) + } else { + rhs + }; + + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } _ => return Err(CompileError::BitwiseOpOnNonInteger), } } - ExprBinaryOp::ShiftLeft => match (lhs_type, rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} - _ => return Err(CompileError::BitwiseOpOnNonInteger), - }, - ExprBinaryOp::ShiftLeftAssign => { - if !lhs.is_address() { - return Err(CompileError::NotAssignable); + ExprBinaryOp::Equal => match (&lhs_type, &rhs_type) { + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + let common_type = a.common_type(&b); + let lhs = if a != &common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Integer(common_type), + }) + } else { + lhs + }; + let rhs = if b != &common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(common_type), + }) + } else { + rhs + }; + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); } - if lhs.cv_type()?.const_ { - return Err(CompileError::AssignToConst); + (PrimitiveType::Integer(_), PrimitiveType::Float(b)) => { + let lhs = Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Float(*b), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); } - match (lhs_type, rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} - _ => return Err(CompileError::BitwiseOpOnNonInteger), + (PrimitiveType::Float(a), PrimitiveType::Integer(_)) => { + let rhs = Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Float(*a), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); } - } - ExprBinaryOp::ShiftRight => match (lhs_type, rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} - _ => return Err(CompileError::BitwiseOpOnNonInteger), - }, - ExprBinaryOp::ShiftRightAssign => { - if !lhs.is_address() { - return Err(CompileError::NotAssignable); + (PrimitiveType::Float(a), PrimitiveType::Float(b)) => { + let common_type = a.common_type(&b); + let lhs = if a != &common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Float(common_type), + }) + } else { + lhs + }; + let rhs = if b != &common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Float(common_type), + }) + } else { + rhs + }; + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); } - if lhs.cv_type()?.const_ { - return Err(CompileError::AssignToConst); + + (PrimitiveType::Pointer(a), PrimitiveType::Pointer(b)) => { + if a != b { + return Err(CompileError::DistinctPointer( + a.as_ref().clone(), + b.as_ref().clone(), + )); + } } + (PrimitiveType::Pointer(a), PrimitiveType::Array(b)) => { + if a != &b.cv_type { + return Err(CompileError::DistinctPointer( + a.as_ref().clone(), + b.cv_type.as_ref().clone(), + )); + } - match (lhs_type, rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} - _ => return Err(CompileError::BitwiseOpOnNonInteger), + let rhs = Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Pointer(b.cv_type.clone()), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); } - } - ExprBinaryOp::Equal => match (&lhs_type, &rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} + (PrimitiveType::Array(a), PrimitiveType::Pointer(b)) => { + if &a.cv_type != b { + return Err(CompileError::DistinctPointer( + a.cv_type.as_ref().clone(), + b.as_ref().clone(), + )); + } - (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + let lhs = Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Pointer(a.cv_type.clone()), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Array(a), PrimitiveType::Array(b)) => { + if a.cv_type != b.cv_type { + return Err(CompileError::DistinctPointer( + a.cv_type.as_ref().clone(), + b.cv_type.as_ref().clone(), + )); + } - (PrimitiveType::Pointer(_), PrimitiveType::Pointer(_)) => {} - (PrimitiveType::Pointer(_), PrimitiveType::Array(_)) => {} - (PrimitiveType::Array(_), PrimitiveType::Pointer(_)) => {} - (PrimitiveType::Array(_), PrimitiveType::Array(_)) => {} + let lhs = Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Pointer(a.cv_type.clone()), + }); + let rhs = Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Pointer(b.cv_type.clone()), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } _ => return Err(CompileError::InvalidOperandType(lhs_type, rhs_type)), }, ExprBinaryOp::NotEqual => match (&lhs_type, &rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + let common_type = a.common_type(&b); + let lhs = if a != &common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Integer(common_type), + }) + } else { + lhs + }; + let rhs = if b != &common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(common_type), + }) + } else { + rhs + }; + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Integer(_), PrimitiveType::Float(b)) => { + let lhs = Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Float(*b), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + + (PrimitiveType::Float(a), PrimitiveType::Integer(_)) => { + let rhs = Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Float(*a), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Float(a), PrimitiveType::Float(b)) => { + let common_type = a.common_type(&b); + let lhs = if a != &common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Float(common_type), + }) + } else { + lhs + }; + let rhs = if b != &common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Float(common_type), + }) + } else { + rhs + }; + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + + (PrimitiveType::Pointer(a), PrimitiveType::Pointer(b)) => { + if a != b { + return Err(CompileError::DistinctPointer( + a.as_ref().clone(), + b.as_ref().clone(), + )); + } + } + (PrimitiveType::Pointer(a), PrimitiveType::Array(b)) => { + if a != &b.cv_type { + return Err(CompileError::DistinctPointer( + a.as_ref().clone(), + b.cv_type.as_ref().clone(), + )); + } - (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + let rhs = Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Pointer(b.cv_type.clone()), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Array(a), PrimitiveType::Pointer(b)) => { + if &a.cv_type != b { + return Err(CompileError::DistinctPointer( + a.cv_type.as_ref().clone(), + b.as_ref().clone(), + )); + } + + let lhs = Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Pointer(a.cv_type.clone()), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Array(a), PrimitiveType::Array(b)) => { + if a.cv_type != b.cv_type { + return Err(CompileError::DistinctPointer( + a.cv_type.as_ref().clone(), + b.cv_type.as_ref().clone(), + )); + } - (PrimitiveType::Pointer(_), PrimitiveType::Pointer(_)) => {} - (PrimitiveType::Pointer(_), PrimitiveType::Array(_)) => {} - (PrimitiveType::Array(_), PrimitiveType::Pointer(_)) => {} - (PrimitiveType::Array(_), PrimitiveType::Array(_)) => {} + let lhs = Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Pointer(a.cv_type.clone()), + }); + let rhs = Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Pointer(b.cv_type.clone()), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } _ => return Err(CompileError::InvalidOperandType(lhs_type, rhs_type)), }, ExprBinaryOp::LessThan => match (&lhs_type, &rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + let common_type = a.common_type(&b); + let lhs = if a != &common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Integer(common_type), + }) + } else { + lhs + }; + let rhs = if b != &common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(common_type), + }) + } else { + rhs + }; + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Integer(_), PrimitiveType::Float(b)) => { + let lhs = Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Float(*b), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } - (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + (PrimitiveType::Float(a), PrimitiveType::Integer(_)) => { + let rhs = Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Float(*a), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Float(a), PrimitiveType::Float(b)) => { + let common_type = a.common_type(&b); + let lhs = if a != &common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Float(common_type), + }) + } else { + lhs + }; + let rhs = if b != &common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Float(common_type), + }) + } else { + rhs + }; + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } - (PrimitiveType::Pointer(_), PrimitiveType::Pointer(_)) => {} - (PrimitiveType::Pointer(_), PrimitiveType::Array(_)) => {} - (PrimitiveType::Array(_), PrimitiveType::Pointer(_)) => {} - (PrimitiveType::Array(_), PrimitiveType::Array(_)) => {} + (PrimitiveType::Pointer(a), PrimitiveType::Pointer(b)) => { + if a != b { + return Err(CompileError::DistinctPointer( + a.as_ref().clone(), + b.as_ref().clone(), + )); + } + } + (PrimitiveType::Pointer(a), PrimitiveType::Array(b)) => { + if a != &b.cv_type { + return Err(CompileError::DistinctPointer( + a.as_ref().clone(), + b.cv_type.as_ref().clone(), + )); + } + + let rhs = Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Pointer(b.cv_type.clone()), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Array(a), PrimitiveType::Pointer(b)) => { + if &a.cv_type != b { + return Err(CompileError::DistinctPointer( + a.cv_type.as_ref().clone(), + b.as_ref().clone(), + )); + } + + let lhs = Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Pointer(a.cv_type.clone()), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Array(a), PrimitiveType::Array(b)) => { + if a.cv_type != b.cv_type { + return Err(CompileError::DistinctPointer( + a.cv_type.as_ref().clone(), + b.cv_type.as_ref().clone(), + )); + } + + let lhs = Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Pointer(a.cv_type.clone()), + }); + let rhs = Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Pointer(b.cv_type.clone()), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } _ => return Err(CompileError::InvalidOperandType(lhs_type, rhs_type)), }, ExprBinaryOp::LessThanOrEqual => match (&lhs_type, &rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + let common_type = a.common_type(&b); + let lhs = if a != &common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Integer(common_type), + }) + } else { + lhs + }; + let rhs = if b != &common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(common_type), + }) + } else { + rhs + }; + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Integer(_), PrimitiveType::Float(b)) => { + let lhs = Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Float(*b), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + + (PrimitiveType::Float(a), PrimitiveType::Integer(_)) => { + let rhs = Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Float(*a), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Float(a), PrimitiveType::Float(b)) => { + let common_type = a.common_type(&b); + let lhs = if a != &common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Float(common_type), + }) + } else { + lhs + }; + let rhs = if b != &common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Float(common_type), + }) + } else { + rhs + }; + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + + (PrimitiveType::Pointer(a), PrimitiveType::Pointer(b)) => { + if a != b { + return Err(CompileError::DistinctPointer( + a.as_ref().clone(), + b.as_ref().clone(), + )); + } + } + (PrimitiveType::Pointer(a), PrimitiveType::Array(b)) => { + if a != &b.cv_type { + return Err(CompileError::DistinctPointer( + a.as_ref().clone(), + b.cv_type.as_ref().clone(), + )); + } - (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + let rhs = Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Pointer(b.cv_type.clone()), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Array(a), PrimitiveType::Pointer(b)) => { + if &a.cv_type != b { + return Err(CompileError::DistinctPointer( + a.cv_type.as_ref().clone(), + b.as_ref().clone(), + )); + } - (PrimitiveType::Pointer(_), PrimitiveType::Pointer(_)) => {} - (PrimitiveType::Pointer(_), PrimitiveType::Array(_)) => {} - (PrimitiveType::Array(_), PrimitiveType::Pointer(_)) => {} - (PrimitiveType::Array(_), PrimitiveType::Array(_)) => {} + let lhs = Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Pointer(a.cv_type.clone()), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Array(a), PrimitiveType::Array(b)) => { + if a.cv_type != b.cv_type { + return Err(CompileError::DistinctPointer( + a.cv_type.as_ref().clone(), + b.cv_type.as_ref().clone(), + )); + } + let lhs = Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Pointer(a.cv_type.clone()), + }); + let rhs = Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Pointer(b.cv_type.clone()), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } _ => return Err(CompileError::InvalidOperandType(lhs_type, rhs_type)), }, ExprBinaryOp::GreaterThan => match (&lhs_type, &rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + let common_type = a.common_type(&b); + let lhs = if a != &common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Integer(common_type), + }) + } else { + lhs + }; + let rhs = if b != &common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(common_type), + }) + } else { + rhs + }; + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Integer(_), PrimitiveType::Float(b)) => { + let lhs = Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Float(*b), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } - (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + (PrimitiveType::Float(a), PrimitiveType::Integer(_)) => { + let rhs = Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Float(*a), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Float(a), PrimitiveType::Float(b)) => { + let common_type = a.common_type(&b); + let lhs = if a != &common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Float(common_type), + }) + } else { + lhs + }; + let rhs = if b != &common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Float(common_type), + }) + } else { + rhs + }; + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } - (PrimitiveType::Pointer(_), PrimitiveType::Pointer(_)) => {} - (PrimitiveType::Pointer(_), PrimitiveType::Array(_)) => {} - (PrimitiveType::Array(_), PrimitiveType::Pointer(_)) => {} - (PrimitiveType::Array(_), PrimitiveType::Array(_)) => {} + (PrimitiveType::Pointer(a), PrimitiveType::Pointer(b)) => { + if a != b { + return Err(CompileError::DistinctPointer( + a.as_ref().clone(), + b.as_ref().clone(), + )); + } + } + (PrimitiveType::Pointer(a), PrimitiveType::Array(b)) => { + if a != &b.cv_type { + return Err(CompileError::DistinctPointer( + a.as_ref().clone(), + b.cv_type.as_ref().clone(), + )); + } + + let rhs = Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Pointer(b.cv_type.clone()), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Array(a), PrimitiveType::Pointer(b)) => { + if &a.cv_type != b { + return Err(CompileError::DistinctPointer( + a.cv_type.as_ref().clone(), + b.as_ref().clone(), + )); + } + + let lhs = Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Pointer(a.cv_type.clone()), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Array(a), PrimitiveType::Array(b)) => { + if a.cv_type != b.cv_type { + return Err(CompileError::DistinctPointer( + a.cv_type.as_ref().clone(), + b.cv_type.as_ref().clone(), + )); + } + + let lhs = Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Pointer(a.cv_type.clone()), + }); + let rhs = Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Pointer(b.cv_type.clone()), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } _ => return Err(CompileError::InvalidOperandType(lhs_type, rhs_type)), }, ExprBinaryOp::GreaterThanOrEqual => match (&lhs_type, &rhs_type) { - (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => {} + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + let common_type = a.common_type(&b); + let lhs = if a != &common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Integer(common_type), + }) + } else { + lhs + }; + let rhs = if b != &common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Integer(common_type), + }) + } else { + rhs + }; + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Integer(_), PrimitiveType::Float(b)) => { + let lhs = Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Float(*b), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + + (PrimitiveType::Float(a), PrimitiveType::Integer(_)) => { + let rhs = Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Float(*a), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Float(a), PrimitiveType::Float(b)) => { + let common_type = a.common_type(&b); + let lhs = if a != &common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Float(common_type), + }) + } else { + lhs + }; + let rhs = if b != &common_type { + Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Float(common_type), + }) + } else { + rhs + }; + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + + (PrimitiveType::Pointer(a), PrimitiveType::Pointer(b)) => { + if a != b { + return Err(CompileError::DistinctPointer( + a.as_ref().clone(), + b.as_ref().clone(), + )); + } + } + (PrimitiveType::Pointer(a), PrimitiveType::Array(b)) => { + if a != &b.cv_type { + return Err(CompileError::DistinctPointer( + a.as_ref().clone(), + b.cv_type.as_ref().clone(), + )); + } - (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => {} - (PrimitiveType::Float(_), PrimitiveType::Float(_)) => {} + let rhs = Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Pointer(b.cv_type.clone()), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Array(a), PrimitiveType::Pointer(b)) => { + if &a.cv_type != b { + return Err(CompileError::DistinctPointer( + a.cv_type.as_ref().clone(), + b.as_ref().clone(), + )); + } + + let lhs = Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Pointer(a.cv_type.clone()), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } + (PrimitiveType::Array(a), PrimitiveType::Array(b)) => { + if a.cv_type != b.cv_type { + return Err(CompileError::DistinctPointer( + a.cv_type.as_ref().clone(), + b.cv_type.as_ref().clone(), + )); + } - (PrimitiveType::Pointer(_), PrimitiveType::Pointer(_)) => {} - (PrimitiveType::Pointer(_), PrimitiveType::Array(_)) => {} - (PrimitiveType::Array(_), PrimitiveType::Pointer(_)) => {} - (PrimitiveType::Array(_), PrimitiveType::Array(_)) => {} + let lhs = Expression::Cast(super::ExprCast { + expr: Box::new(lhs), + type_: PrimitiveType::Pointer(a.cv_type.clone()), + }); + let rhs = Expression::Cast(super::ExprCast { + expr: Box::new(rhs), + type_: PrimitiveType::Pointer(b.cv_type.clone()), + }); + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); + } _ => return Err(CompileError::InvalidOperandType(lhs_type, rhs_type)), }, @@ -1908,6 +3704,19 @@ impl Context { if !rhs_type.is_implicitly_castable(&lhs_type) { return Err(CompileError::InvalidOperandType(lhs_type, rhs_type)); } + let rhs = if lhs_type != rhs_type { + Expression::Cast(expression::ExprCast { + expr: Box::new(rhs), + type_: lhs_type.clone(), + }) + } else { + rhs + }; + return Ok(Expression::Binary(expression::ExprBinary { + op: expr.op, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + })); } } diff --git a/src/ast2/error.rs b/src/ast2/error.rs index 11a5c01..4262a47 100644 --- a/src/ast2/error.rs +++ b/src/ast2/error.rs @@ -1,4 +1,4 @@ -use super::PrimitiveType; +use super::{CVType, PrimitiveType}; #[derive(Debug, Clone)] pub enum CompileError { @@ -94,4 +94,9 @@ pub enum CompileError { InvalidOperandType(PrimitiveType, PrimitiveType), EnumValueNotInteger, + + InvalidIfCondition(PrimitiveType), + InitializeTypeMismatch(PrimitiveType, PrimitiveType), + + DistinctPointer(CVType, CVType), } diff --git a/src/ast2/expression.rs b/src/ast2/expression.rs index 5e4d866..aea1fb8 100644 --- a/src/ast2/expression.rs +++ b/src/ast2/expression.rs @@ -1,5 +1,6 @@ use crate::ast; +use super::Address; use super::CompileError; use super::Float; use super::Integer; @@ -11,7 +12,7 @@ pub enum Expression { Signed(i64, Integer), Unsigned(u64, Integer), Float(f64, Float), - String(String), + String(Address), Variable(VariableInfo), @@ -27,24 +28,75 @@ pub enum Expression { InitializerList(ExprInitializerList), } impl Expression { - /// is this expression returns an address upon generating instructions? + /// If this returns true, + /// InstructionGenerator::emit_expression(this) emit address of this expression. + /// User must read sizeof(this) bytes from the address in RAX register. pub fn is_address(&self) -> bool { match self { Expression::Signed(_, _) | Expression::Unsigned(_, _) | Expression::Float(_, _) => { false } - Expression::String(_) => unimplemented!("is_address - String literal"), - Expression::Variable(_) => true, - Expression::Conditional(_) => false, + Expression::String(_) => false, + Expression::Variable(var) => match &var.cv_type.type_ { + PrimitiveType::Array(_) => true, + _ => false, + }, + Expression::Conditional(expr) => { + expr.else_expr.is_address() && expr.then_expr.is_address() + } Expression::Cast(_) => false, Expression::Member(_) => true, Expression::Arrow(_) => true, Expression::Paren(_) => false, Expression::Bracket(_) => true, Expression::Unary(expr) => match expr.op { - _ => false, + ExprUnaryOp::AddressOf => false, + ExprUnaryOp::BitwiseNot => false, + ExprUnaryOp::DecrementPost => false, + ExprUnaryOp::DecrementPre => true, + ExprUnaryOp::IncrementPost => false, + ExprUnaryOp::IncrementPre => true, + ExprUnaryOp::LogicalNot => false, + ExprUnaryOp::Minus => false, + ExprUnaryOp::Dereference => true, + ExprUnaryOp::Plus => unreachable!("Unary Plus"), + }, + Expression::Binary(expr) => match expr.op { + ExprBinaryOp::Add + | ExprBinaryOp::Sub + | ExprBinaryOp::Mul + | ExprBinaryOp::Div + | ExprBinaryOp::Mod => false, + + ExprBinaryOp::BitwiseAnd | ExprBinaryOp::BitwiseOr | ExprBinaryOp::BitwiseXor => { + false + } + + ExprBinaryOp::ShiftLeft | ExprBinaryOp::ShiftRight => false, + + ExprBinaryOp::Equal + | ExprBinaryOp::NotEqual + | ExprBinaryOp::LessThan + | ExprBinaryOp::LessThanOrEqual + | ExprBinaryOp::GreaterThan + | ExprBinaryOp::GreaterThanOrEqual + | ExprBinaryOp::LogicalAnd + | ExprBinaryOp::LogicalOr => false, + + ExprBinaryOp::AddAssign + | ExprBinaryOp::SubAssign + | ExprBinaryOp::MulAssign + | ExprBinaryOp::DivAssign + | ExprBinaryOp::ModAssign + | ExprBinaryOp::BitwiseAndAssign + | ExprBinaryOp::BitwiseOrAssign + | ExprBinaryOp::BitwiseXorAssign + | ExprBinaryOp::ShiftLeftAssign + | ExprBinaryOp::ShiftRightAssign + | ExprBinaryOp::Assign => true, + + ExprBinaryOp::Comma => expr.rhs.is_address(), }, - Expression::Binary(_) => false, Expression::InitializerList(_) => false, } } @@ -145,7 +197,6 @@ impl Expression { }; CVType::from_primitive(type_) } - ExprBinaryOp::AddAssign => lhs_type, ExprBinaryOp::Sub => { let type_ = match (lhs_type.type_, rhs_type.type_) { (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { @@ -154,12 +205,6 @@ impl Expression { (PrimitiveType::Integer(a), PrimitiveType::Float(b)) => { PrimitiveType::Float(b) } - (PrimitiveType::Integer(a), PrimitiveType::Pointer(b)) => { - PrimitiveType::Pointer(b) - } - (PrimitiveType::Integer(a), PrimitiveType::Array(b)) => { - PrimitiveType::Pointer(b.cv_type) - } (PrimitiveType::Float(a), PrimitiveType::Integer(b)) => { PrimitiveType::Float(a) @@ -179,8 +224,7 @@ impl Expression { }; CVType::from_primitive(type_) } - ExprBinaryOp::SubAssign => lhs_type, - ExprBinaryOp::Mul => { + ExprBinaryOp::Mul | ExprBinaryOp::Div => { let type_ = match (lhs_type.type_, rhs_type.type_) { (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { PrimitiveType::Integer(a.common_type(&b)) @@ -200,28 +244,6 @@ impl Expression { }; CVType::from_primitive(type_) } - ExprBinaryOp::MulAssign => lhs_type, - ExprBinaryOp::Div => { - let type_ = match (lhs_type.type_, rhs_type.type_) { - (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { - PrimitiveType::Integer(a.common_type(&b)) - } - (PrimitiveType::Integer(a), PrimitiveType::Float(b)) => { - PrimitiveType::Float(b) - } - - (PrimitiveType::Float(a), PrimitiveType::Integer(b)) => { - PrimitiveType::Float(a) - } - (PrimitiveType::Float(a), PrimitiveType::Float(b)) => { - PrimitiveType::Float(a.common_type(&b)) - } - - _ => unreachable!("Div expression type"), - }; - CVType::from_primitive(type_) - } - ExprBinaryOp::DivAssign => lhs_type, ExprBinaryOp::Mod => { let type_ = match (lhs_type.type_, rhs_type.type_) { (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { @@ -232,88 +254,42 @@ impl Expression { }; CVType::from_primitive(type_) } - ExprBinaryOp::ModAssign => lhs_type, - ExprBinaryOp::BitwiseAnd => { - let type_ = match (lhs_type.type_, rhs_type.type_) { - (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { - PrimitiveType::Integer(a.common_type(&b)) - } - - _ => unreachable!("BitAnd expression type"), - }; - CVType::from_primitive(type_) - } - ExprBinaryOp::BitwiseAndAssign => lhs_type, - ExprBinaryOp::BitwiseOr => { - let type_ = match (lhs_type.type_, rhs_type.type_) { - (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { - PrimitiveType::Integer(a.common_type(&b)) - } - - _ => unreachable!("BitOr expression type"), - }; - CVType::from_primitive(type_) + ExprBinaryOp::BitwiseAnd + | ExprBinaryOp::BitwiseOr + | ExprBinaryOp::BitwiseXor => match (lhs_type.type_, rhs_type.type_) { + (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { + CVType::from_primitive(PrimitiveType::Integer(a.common_type(&b))) + } + + _ => unreachable!("BitOp expression type"), + }, + ExprBinaryOp::ShiftLeft | ExprBinaryOp::ShiftRight => { + CVType::from_primitive(lhs_type.type_) } - ExprBinaryOp::BitwiseOrAssign => lhs_type, - ExprBinaryOp::BitwiseXor => { - let type_ = match (lhs_type.type_, rhs_type.type_) { - (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { - PrimitiveType::Integer(a.common_type(&b)) - } - - _ => unreachable!("BitAnd expression type"), - }; - CVType::from_primitive(type_) + ExprBinaryOp::Equal + | ExprBinaryOp::NotEqual + | ExprBinaryOp::LessThan + | ExprBinaryOp::LessThanOrEqual + | ExprBinaryOp::GreaterThan + | ExprBinaryOp::GreaterThanOrEqual + | ExprBinaryOp::LogicalAnd + | ExprBinaryOp::LogicalOr => { + CVType::from_primitive(PrimitiveType::Integer(Integer::Int32)) } - ExprBinaryOp::BitwiseXorAssign => lhs_type, - ExprBinaryOp::ShiftLeft => { - let type_ = match (lhs_type.type_, rhs_type.type_) { - (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { - PrimitiveType::Integer(a.common_type(&b)) - } - _ => unreachable!("BitAnd expression type"), - }; - CVType::from_primitive(type_) - } - ExprBinaryOp::ShiftLeftAssign => lhs_type, - ExprBinaryOp::ShiftRight => { - let type_ = match (lhs_type.type_, rhs_type.type_) { - (PrimitiveType::Integer(a), PrimitiveType::Integer(b)) => { - PrimitiveType::Integer(a.common_type(&b)) - } + ExprBinaryOp::AddAssign + | ExprBinaryOp::SubAssign + | ExprBinaryOp::MulAssign + | ExprBinaryOp::DivAssign + | ExprBinaryOp::ModAssign + | ExprBinaryOp::BitwiseAndAssign + | ExprBinaryOp::BitwiseOrAssign + | ExprBinaryOp::BitwiseXorAssign + | ExprBinaryOp::ShiftLeftAssign + | ExprBinaryOp::ShiftRightAssign + | ExprBinaryOp::Assign => lhs_type, - _ => unreachable!("BitAnd expression type"), - }; - CVType::from_primitive(type_) - } - ExprBinaryOp::ShiftRightAssign => lhs_type, - ExprBinaryOp::Equal => { - CVType::from_primitive(PrimitiveType::Integer(Integer::Int32)) - } - ExprBinaryOp::NotEqual => { - CVType::from_primitive(PrimitiveType::Integer(Integer::Int32)) - } - ExprBinaryOp::LessThan => { - CVType::from_primitive(PrimitiveType::Integer(Integer::Int32)) - } - ExprBinaryOp::LessThanOrEqual => { - CVType::from_primitive(PrimitiveType::Integer(Integer::Int32)) - } - ExprBinaryOp::GreaterThan => { - CVType::from_primitive(PrimitiveType::Integer(Integer::Int32)) - } - ExprBinaryOp::GreaterThanOrEqual => { - CVType::from_primitive(PrimitiveType::Integer(Integer::Int32)) - } - ExprBinaryOp::LogicalAnd => { - CVType::from_primitive(PrimitiveType::Integer(Integer::Int32)) - } - ExprBinaryOp::LogicalOr => { - CVType::from_primitive(PrimitiveType::Integer(Integer::Int32)) - } ExprBinaryOp::Comma => rhs_type, - ExprBinaryOp::Assign => lhs_type, } } }) diff --git a/src/ast2/statement.rs b/src/ast2/statement.rs index 180f1e4..589e813 100644 --- a/src/ast2/statement.rs +++ b/src/ast2/statement.rs @@ -56,6 +56,7 @@ pub struct StmtIf { pub struct StmtSwitch { pub value: Expression, pub cases: Vec, + pub default: Option, } #[derive(Debug, Clone)] pub struct StmtSwitchCase { @@ -107,4 +108,5 @@ pub struct StmtVariableDeclaration { #[derive(Debug, Clone)] pub struct TranslationUnit { pub statements: Vec, + pub text: Vec, } diff --git a/src/ast2/typename.rs b/src/ast2/typename.rs index 747fc3f..5b38017 100644 --- a/src/ast2/typename.rs +++ b/src/ast2/typename.rs @@ -86,13 +86,6 @@ impl Float { Float::Float64 => 8, } } - pub fn from_size(size: usize) -> Self { - match size { - 4 => Float::Float32, - 8 => Float::Float64, - _ => panic!("Invalid size"), - } - } pub fn common_type(&self, other: &Float) -> Self { match (self, other) { (Float::Float64, _) => Float::Float64, @@ -118,10 +111,40 @@ pub enum PrimitiveType { } impl PrimitiveType { pub fn is_castable(&self, to: &PrimitiveType) -> bool { - unimplemented!("is_castable") + match (self, to) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => true, + (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => true, + (PrimitiveType::Integer(_), PrimitiveType::Pointer(_)) => true, + + (PrimitiveType::Float(_), PrimitiveType::Integer(_)) => true, + (PrimitiveType::Float(_), PrimitiveType::Float(_)) => true, + + (PrimitiveType::Pointer(_), PrimitiveType::Pointer(_)) => true, + (PrimitiveType::Pointer(_), PrimitiveType::Integer(_)) => true, + + (PrimitiveType::Array(_), PrimitiveType::Integer(_)) => true, + (PrimitiveType::Array(_), PrimitiveType::Pointer(_)) => true, + + _ => false, + } } pub fn is_implicitly_castable(&self, to: &PrimitiveType) -> bool { - unimplemented!("is_implicitly_castable") + match (self, to) { + (PrimitiveType::Integer(_), PrimitiveType::Integer(_)) => true, + (PrimitiveType::Integer(_), PrimitiveType::Float(_)) => true, + + (PrimitiveType::Float(_), PrimitiveType::Float(_)) => true, + + (PrimitiveType::Pointer(from), PrimitiveType::Pointer(to)) => { + from.type_.is_implicitly_castable(&to.type_) + } + + (PrimitiveType::Array(from), PrimitiveType::Pointer(to)) => { + from.cv_type.type_.is_implicitly_castable(&to.type_) + } + + _ => false, + } } pub fn is_bool_castable(&self) -> bool { matches!( @@ -405,6 +428,13 @@ impl CVType { } } +impl std::ops::Deref for CVType { + type Target = PrimitiveType; + fn deref(&self) -> &Self::Target { + &self.type_ + } +} + #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct StorageQualifier { pub static_: bool, diff --git a/src/ast2/variable.rs b/src/ast2/variable.rs index da62324..49da9cc 100644 --- a/src/ast2/variable.rs +++ b/src/ast2/variable.rs @@ -45,6 +45,8 @@ pub enum Address { Local(usize), /// index on function array Function(usize), + /// constant Text section + Text(usize), } impl Address { @@ -57,19 +59,37 @@ impl Address { pub fn is_function(&self) -> bool { matches!(self, Address::Function(_)) } + pub fn is_text(&self) -> bool { + matches!(self, Address::Text(_)) + } + + /* + xxx 61 bits + ^^^ ^^^^^ actual address + ||| + ^^^ address type specifier + 000 : Global + 001 : Local + 010 : Function + 011 : Text + */ pub fn into_u64(self) -> u64 { match self { - Address::Global(x) => (x as u64) | (1u64 << 63), - Address::Local(x) => (x as u64) | (1u64 << 62), - Address::Function(x) => (x as u64) | (3u64 << 62), + Address::Global(x) => (x as u64) | (0b000u64 << 61), + Address::Local(x) => (x as u64) | (0b001u64 << 61), + Address::Function(x) => (x as u64) | (0b010u64 << 61), + Address::Text(x) => (x as u64) | (0b011u64 << 61), } } pub fn from_u64(x: u64) -> Self { - match x >> 62 { - 1 => Address::Global((x & !(1u64 << 63)) as usize), - 2 => Address::Local((x & !(1u64 << 62)) as usize), - 3 => Address::Function((x & !(3u64 << 62)) as usize), + let specifier = x >> 61; + let address = (x & ((1u64 << 61) - 1)) as usize; + match specifier { + 0 => Address::Global(address), + 1 => Address::Local(address), + 2 => Address::Function(address), + 3 => Address::Text(address), _ => unreachable!("invalid address"), } } diff --git a/src/main.rs b/src/main.rs index 8471bc8..d056b73 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,7 @@ mod ast; mod ast2; mod preprocess; mod token; -// mod virtualmachine; +mod virtualmachine; fn main() { println!("Enter your code (and ^D for EOF):"); @@ -97,25 +97,27 @@ fn main() { }; println!("{:#?}", translation_unit); - /* - // generate instructions println!("{:=^80}", ""); println!("{:=^80}", "Phase5: Generating Instructions"); println!("{:=^80}", ""); - println!("ADDR | {:-^73}", "Result"); - let mut instructions: InstructionGenerator = InstructionGenerator::new(); - translation_unit.emit(&mut instructions); - - println!("Instructions: "); - for (id, instruction) in instructions.instructions.iter().enumerate() { - if id == instructions.start_address { - println!("{: ^2}{:-^78}", "", "Start Address"); + let mut context = virtualmachine::InstructionGenerator::new(); + let vm = match context.emit(translation_unit) { + Ok(vm) => vm, + Err(err) => { + println!("Error: {:?}", err); + return; } + }; + + println!("ADDR | {:-^73}", "Result"); + + for (id, instruction) in vm.instructions.iter().enumerate() { println!("{:4}: {:?}", id, instruction); } + /* // execute instructions println!("{:=^80}", ""); println!("{:=^80}", "Phase6: Executing Instructions"); diff --git a/src/virtualmachine/generator.rs b/src/virtualmachine/generator.rs index 976cc57..6f867d7 100644 --- a/src/virtualmachine/generator.rs +++ b/src/virtualmachine/generator.rs @@ -1,11 +1,20 @@ +use std::collections::HashMap; + use super::Instruction; use super::LabelType; +use super::Operand; +use super::SizeType; use super::VirtualMachine; use crate::ast2; use ast2::Address; use ast2::CompileError; +use ast2::ExprBinaryOp; +use ast2::ExprUnaryOp; use ast2::Expression; +use ast2::Float; +use ast2::Integer; +use ast2::PrimitiveType; use ast2::Statement; use ast2::VariableInfo; @@ -20,13 +29,7 @@ pub struct InstructionGenerator { /// default, break for switch statement pub label_stack: Vec<(LabelType, LabelType)>, - /// where constant data is stored - /// for same-address system with stack data, it will be merged into stack upon program execution - /// - /// commonly, this is used for read-only data - /// but we don't have `const` qualifier yet - /// so it is mutable ... - pub text_section: Vec, + pub(crate) user_defined_labels: HashMap, } impl InstructionGenerator { pub fn new() -> Self { @@ -34,7 +37,7 @@ impl InstructionGenerator { instructions: Vec::new(), labels: Vec::new(), label_stack: Vec::new(), - text_section: Vec::new(), + user_defined_labels: HashMap::new(), } } @@ -63,6 +66,8 @@ impl InstructionGenerator { .map(|x| x.unwrap()) .collect(); vm.instructions = std::mem::take(&mut self.instructions); + // @TODO functions + vm.text = translation_unit.text; Ok(vm) } @@ -89,18 +94,11 @@ impl InstructionGenerator { } } - pub fn emit_expression(&mut self, expression: Expression) -> Result<(), CompileError> { + pub fn emit_expression(&mut self, expression: Expression) -> Result { match expression { - Expression::I8(expr) => self.emit_expression_i8(expr), - Expression::I16(expr) => self.emit_expression_i16(expr), - Expression::I32(expr) => self.emit_expression_i32(expr), - Expression::I64(expr) => self.emit_expression_i64(expr), - Expression::U8(expr) => self.emit_expression_u8(expr), - Expression::U16(expr) => self.emit_expression_u16(expr), - Expression::U32(expr) => self.emit_expression_u32(expr), - Expression::U64(expr) => self.emit_expression_u64(expr), - Expression::F32(expr) => self.emit_expression_f32(expr), - Expression::F64(expr) => self.emit_expression_f64(expr), + Expression::Signed(value, type_) => self.emit_expression_integer(value as u64, type_), + Expression::Unsigned(value, type_) => self.emit_expression_integer(value, type_), + Expression::Float(value, type_) => self.emit_expression_float(value, type_), Expression::String(expr) => self.emit_expression_string(expr), Expression::Variable(expr) => self.emit_expression_variable(expr), Expression::Conditional(expr) => self.emit_expression_conditional(expr), @@ -114,15 +112,51 @@ impl InstructionGenerator { Expression::InitializerList(expr) => self.emit_expression_initializerlist(expr), } } - pub fn emit_expression_derefed(&mut self, expression: Expression) -> Result<(), CompileError> { - let size = expression.cv_type()?.type_.sizeof()?; + pub fn emit_expression_derefed( + &mut self, + expression: Expression, + ) -> Result { if expression.is_address() { + let size = expression.cv_type()?.type_.sizeof()?; self.emit_expression(expression)?; - self.instructions.push(Instruction::Deref(size)); + match size { + 1 => { + self.instructions.push(Instruction::Move( + SizeType::Byte, + Operand::Deref(0), + Operand::Register(0), + )); + Ok(SizeType::Byte) + } + 2 => { + self.instructions.push(Instruction::Move( + SizeType::Word, + Operand::Deref(0), + Operand::Register(0), + )); + Ok(SizeType::Word) + } + 4 => { + self.instructions.push(Instruction::Move( + SizeType::DWord, + Operand::Deref(0), + Operand::Register(0), + )); + Ok(SizeType::DWord) + } + 8 => { + self.instructions.push(Instruction::Move( + SizeType::QWord, + Operand::Deref(0), + Operand::Register(0), + )); + Ok(SizeType::QWord) + } + _ => unreachable!("emit_expression_derefed: {:?}", size), + } } else { - self.emit_expression(expression)?; + self.emit_expression(expression) } - Ok(()) } } @@ -131,117 +165,1352 @@ impl InstructionGenerator { &mut self, stmt: ast2::StmtExpression, ) -> Result<(), CompileError> { - self.emit_expression(*stmt.expr) - } - fn emit_statement_labeled(&mut self, stmt: ast2::StmtLabeled) -> Result<(), CompileError> {} - fn emit_statement_goto(&mut self, stmt: ast2::StmtGoto) -> Result<(), CompileError> {} - fn emit_statement_compound(&mut self, stmt: ast2::StmtCompound) -> Result<(), CompileError> {} - fn emit_statement_if(&mut self, stmt: ast2::StmtIf) -> Result<(), CompileError> {} - fn emit_statement_switch(&mut self, stmt: ast2::StmtSwitch) -> Result<(), CompileError> {} - fn emit_statement_continue(&mut self) -> Result<(), CompileError> {} - fn emit_statement_break(&mut self) -> Result<(), CompileError> {} - fn emit_statement_return(&mut self, stmt: ast2::StmtReturn) -> Result<(), CompileError> {} - fn emit_statement_for(&mut self, stmt: ast2::StmtFor) -> Result<(), CompileError> {} - fn emit_statement_while(&mut self, stmt: ast2::StmtWhile) -> Result<(), CompileError> {} - fn emit_statement_dowhile(&mut self, stmt: ast2::StmtDoWhile) -> Result<(), CompileError> {} - fn emit_statement_variable_declaration( - &mut self, - stmt: ast2::StmtVariableDeclaration, - ) -> Result<(), CompileError> { + self.emit_expression(stmt.expression)?; + Ok(()) } -} + fn emit_statement_labeled(&mut self, stmt: ast2::StmtLabeled) -> Result<(), CompileError> { + let name = stmt.label.borrow().name.clone(); -impl InstructionGenerator { - fn emit_expression_i8(&mut self, expr: i8) -> Result<(), CompileError> { - self.instructions.push(Instruction::I64(expr as i64)); - Ok(()) + let label = if let Some(label) = self.user_defined_labels.get(&name) { + *label + } else { + let label = self.generate_label(); + self.user_defined_labels.insert(name.clone(), label); + label + }; + self.set_label(label); + self.emit_statement(*stmt.statement) } - fn emit_expression_i16(&mut self, expr: i16) -> Result<(), CompileError> { - self.instructions.push(Instruction::I64(expr as i64)); + fn emit_statement_goto(&mut self, stmt: ast2::StmtGoto) -> Result<(), CompileError> { + let name = stmt.label.borrow().name.clone(); + + let label = if let Some(label) = self.user_defined_labels.get(&name) { + *label + } else { + let label = self.generate_label(); + self.user_defined_labels.insert(name.clone(), label); + label + }; + + self.instructions.push(Instruction::Jump(label)); + Ok(()) } - fn emit_expression_i32(&mut self, expr: i32) -> Result<(), CompileError> { - self.instructions.push(Instruction::I64(expr as i64)); + fn emit_statement_compound(&mut self, stmt: ast2::StmtCompound) -> Result<(), CompileError> { + for s in stmt.statements { + self.emit_statement(s)?; + } Ok(()) } - fn emit_expression_i64(&mut self, expr: i64) -> Result<(), CompileError> { - self.instructions.push(Instruction::I64(expr)); + fn emit_statement_if(&mut self, stmt: ast2::StmtIf) -> Result<(), CompileError> { + let else_label = self.generate_label(); + let end_label = self.generate_label(); + let cond_size = self.emit_expression_derefed(stmt.condition)?; + + self.instructions.push(Instruction::JumpZero( + cond_size, + Operand::Register(0), + else_label, + )); + self.emit_statement(*stmt.then)?; + + if let Some(else_stmt) = stmt.else_ { + self.instructions.push(Instruction::Jump(end_label)); + self.set_label(else_label); + self.emit_statement(*else_stmt)?; + } else { + self.set_label(else_label); + } + self.set_label(end_label); Ok(()) } - fn emit_expression_u8(&mut self, expr: u8) -> Result<(), CompileError> { - self.instructions.push(Instruction::U64(expr as u64)); + fn emit_statement_switch(&mut self, stmt: ast2::StmtSwitch) -> Result<(), CompileError> { + unimplemented!("emit_statement_switch") + } + fn emit_statement_continue(&mut self) -> Result<(), CompileError> { + let (continue_label, _) = self.label_stack.last().unwrap(); + self.instructions.push(Instruction::Jump(*continue_label)); Ok(()) } - fn emit_expression_u16(&mut self, expr: u16) -> Result<(), CompileError> { - self.instructions.push(Instruction::U64(expr as u64)); + fn emit_statement_break(&mut self) -> Result<(), CompileError> { + let (_, end_label) = self.label_stack.last().unwrap(); + self.instructions.push(Instruction::Jump(*end_label)); Ok(()) } - fn emit_expression_u32(&mut self, expr: u32) -> Result<(), CompileError> { - self.instructions.push(Instruction::U64(expr as u64)); + fn emit_statement_return(&mut self, stmt: ast2::StmtReturn) -> Result<(), CompileError> { + unimplemented!("emit_statement_return") + } + fn emit_statement_for(&mut self, stmt: ast2::StmtFor) -> Result<(), CompileError> { + let start_label = self.generate_label(); + let continue_label = self.generate_label(); + let end_label = self.generate_label(); + + self.label_stack.push((continue_label, end_label)); + + self.emit_statement(*stmt.init)?; + + self.set_label(start_label); + let cond_size = self.emit_expression_derefed(stmt.condition)?; + self.instructions.push(Instruction::JumpZero( + cond_size, + Operand::Register(0), + end_label, + )); + + self.emit_statement(*stmt.body)?; + self.set_label(continue_label); + if let Some(next) = stmt.next { + self.emit_expression(next)?; + } + self.instructions.push(Instruction::Jump(start_label)); + + self.set_label(end_label); + self.label_stack.pop(); + Ok(()) } - fn emit_expression_u64(&mut self, expr: u64) -> Result<(), CompileError> { - self.instructions.push(Instruction::U64(expr)); + fn emit_statement_while(&mut self, stmt: ast2::StmtWhile) -> Result<(), CompileError> { + let continue_label = self.generate_label(); + let end_label = self.generate_label(); + + self.label_stack.push((continue_label, end_label)); + self.set_label(continue_label); + let cond_size = self.emit_expression_derefed(stmt.condition)?; + self.instructions.push(Instruction::JumpZero( + cond_size, + Operand::Register(0), + end_label, + )); + + self.emit_statement(*stmt.body)?; + self.instructions.push(Instruction::Jump(continue_label)); + self.set_label(end_label); + self.label_stack.pop(); + Ok(()) } - fn emit_expression_f32(&mut self, expr: f32) -> Result<(), CompileError> { - let bits = expr.to_bits(); - self.instructions.push(Instruction::U64(bits as u64)); + fn emit_statement_dowhile(&mut self, stmt: ast2::StmtDoWhile) -> Result<(), CompileError> { + let start_label = self.generate_label(); + let continue_label = self.generate_label(); + let end_label = self.generate_label(); + + self.label_stack.push((continue_label, end_label)); + self.set_label(start_label); + self.emit_statement(*stmt.body)?; + + self.set_label(continue_label); + let cond_size = self.emit_expression_derefed(stmt.condition)?; + self.instructions.push(Instruction::JumpZero( + cond_size, + Operand::Register(0), + end_label, + )); + self.instructions.push(Instruction::Jump(start_label)); + self.set_label(end_label); + self.label_stack.pop(); + Ok(()) } - fn emit_expression_f64(&mut self, expr: f64) -> Result<(), CompileError> { - let bits = expr.to_bits(); - self.instructions.push(Instruction::U64(bits)); + fn emit_statement_variable_declaration( + &mut self, + stmt: ast2::StmtVariableDeclaration, + ) -> Result<(), CompileError> { + for (var, init) in stmt.pairs.into_iter() { + let addr = var.address.into_u64(); + if init.is_address() { + let type_size = init.cv_type()?.type_.sizeof()?; + self.emit_expression(init)?; + self.instructions.push(Instruction::Move( + SizeType::QWord, + Operand::Constant(addr), + Operand::Register(2), + )); + self.instructions.push(Instruction::Memcpy( + type_size, + Operand::Register(0), + Operand::Register(2), + )); + } else { + let size = self.emit_expression(init)?; + self.instructions.push(Instruction::Move( + SizeType::QWord, + Operand::Constant(addr), + Operand::Register(2), + )); + self.instructions.push(Instruction::Move( + size, + Operand::Register(0), + Operand::Deref(2), + )); + } + } Ok(()) } - fn emit_expression_string(&mut self, expr: String) -> Result<(), CompileError> { - unimplemented!("emit_expression_string"); +} + +impl InstructionGenerator { + fn emit_expression_integer( + &mut self, + value: u64, + type_: Integer, + ) -> Result { + match type_ { + Integer::Int8 => { + self.instructions.push(Instruction::Move( + SizeType::Byte, + Operand::Constant(value), + Operand::Register(0), + )); + Ok(SizeType::Byte) + } + Integer::Int16 => { + self.instructions.push(Instruction::Move( + SizeType::Word, + Operand::Constant(value), + Operand::Register(0), + )); + Ok(SizeType::Word) + } + Integer::Int32 => { + self.instructions.push(Instruction::Move( + SizeType::DWord, + Operand::Constant(value), + Operand::Register(0), + )); + Ok(SizeType::DWord) + } + Integer::Int64 => { + self.instructions.push(Instruction::Move( + SizeType::QWord, + Operand::Constant(value), + Operand::Register(0), + )); + Ok(SizeType::QWord) + } + Integer::UInt8 => { + self.instructions.push(Instruction::Move( + SizeType::Byte, + Operand::Constant(value), + Operand::Register(0), + )); + Ok(SizeType::Byte) + } + Integer::UInt16 => { + self.instructions.push(Instruction::Move( + SizeType::Word, + Operand::Constant(value), + Operand::Register(0), + )); + Ok(SizeType::Word) + } + Integer::UInt32 => { + self.instructions.push(Instruction::Move( + SizeType::DWord, + Operand::Constant(value), + Operand::Register(0), + )); + Ok(SizeType::DWord) + } + Integer::UInt64 => { + self.instructions.push(Instruction::Move( + SizeType::QWord, + Operand::Constant(value), + Operand::Register(0), + )); + Ok(SizeType::QWord) + } + } } - fn emit_expression_variable(&mut self, expr: VariableInfo) -> Result<(), CompileError> { - self.instructions - .push(Instruction::U64(expr.address.into_u64())); - Ok(()) + fn emit_expression_float( + &mut self, + value: f64, + type_: Float, + ) -> Result { + match type_ { + Float::Float32 => { + let bits = (value as f32).to_bits(); + self.instructions.push(Instruction::Move( + SizeType::DWord, + Operand::Constant(bits as u64), + Operand::Register(0), + )); + Ok(SizeType::DWord) + } + Float::Float64 => { + let bits = value.to_bits(); + self.instructions.push(Instruction::Move( + SizeType::QWord, + Operand::Constant(bits), + Operand::Register(0), + )); + Ok(SizeType::QWord) + } + } + } + fn emit_expression_string(&mut self, addr: Address) -> Result { + let addr = addr.into_u64(); + self.instructions.push(Instruction::Move( + SizeType::QWord, + Operand::Constant(addr), + Operand::Register(0), + )); + Ok(SizeType::QWord) + } + fn emit_expression_variable(&mut self, expr: VariableInfo) -> Result { + let addr = expr.address.into_u64(); + self.instructions.push(Instruction::Move( + SizeType::QWord, + Operand::Constant(addr), + Operand::Register(0), + )); + Ok(SizeType::QWord) } fn emit_expression_conditional( &mut self, expr: ast2::ExprConditional, - ) -> Result<(), CompileError> { + ) -> Result { let else_label = self.generate_label(); let end_label = self.generate_label(); - let cond_size = expr.cond.cv_type()?.type_.sizeof()?; - - self.emit_expression_derefed(*expr.cond)?; - self.instructions - .push(Instruction::JumpZero(cond_size, else_label)); - - let then_size = expr.then_expr.cv_type()?.type_.sizeof()?; - self.emit_expression_derefed(*expr.then_expr)?; - self.instructions.push(Instruction::Jump(end_label)); - self.set_label(else_label); - self.emit_expression_derefed(*expr.else_expr)?; - self.else_expr.emit(instructions); - if self.else_expr.is_return_reference(instructions) { - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Derefed(0, 0), - operand_to: Operand::Register(1), - })); - instructions.push(Instruction::MoveRegister(MoveRegister { - operand_from: Operand::Register(1), - operand_to: Operand::Register(0), - })); + + let cond_size = self.emit_expression_derefed(*expr.cond)?; + self.instructions.push(Instruction::JumpZero( + cond_size, + Operand::Register(0), + else_label, + )); + + if expr.else_expr.is_address() && expr.then_expr.is_address() { + self.emit_expression(*expr.then_expr)?; + self.instructions.push(Instruction::Jump(end_label)); + self.set_label(else_label); + let ret = self.emit_expression(*expr.else_expr)?; + self.set_label(end_label); + Ok(ret) + } else { + self.emit_expression_derefed(*expr.then_expr)?; + self.instructions.push(Instruction::Jump(end_label)); + self.set_label(else_label); + let ret = self.emit_expression_derefed(*expr.else_expr)?; + self.set_label(end_label); + Ok(ret) } - instructions.set_label(&end_label); - } - fn emit_expression_cast(&mut self, expr: ast2::ExprCast) -> Result<(), CompileError> {} - fn emit_expression_member(&mut self, expr: ast2::ExprMember) -> Result<(), CompileError> {} - fn emit_expression_arrow(&mut self, expr: ast2::ExprMember) -> Result<(), CompileError> {} - fn emit_expression_paren(&mut self, expr: ast2::ExprParen) -> Result<(), CompileError> {} - fn emit_expression_bracket(&mut self, expr: ast2::ExprBracket) -> Result<(), CompileError> {} - fn emit_expression_unary(&mut self, expr: ast2::ExprUnary) -> Result<(), CompileError> {} - fn emit_expression_binary(&mut self, expr: ast2::ExprBinary) -> Result<(), CompileError> {} + } + fn emit_expression_cast(&mut self, expr: ast2::ExprCast) -> Result { + let from_type = expr.expr.cv_type()?.type_; + + match (from_type, expr.type_) { + (PrimitiveType::Integer(from), PrimitiveType::Integer(to)) => { + self.emit_expression_derefed(*expr.expr)?; + let from_size = from.sizeof(); + let to_size = to.sizeof(); + if from_size != to_size { + self.instructions.push(Instruction::I2I(from, to)); + } + Ok(SizeType::from_size(to_size)) + } + (PrimitiveType::Integer(from), PrimitiveType::Float(to)) => { + self.emit_expression_derefed(*expr.expr)?; + self.instructions.push(Instruction::I2F(from, to)); + Ok(SizeType::from_size(to.sizeof())) + } + (PrimitiveType::Integer(from), PrimitiveType::Pointer(_)) => { + self.emit_expression_derefed(*expr.expr)?; + if from.sizeof() != 8 { + self.instructions + .push(Instruction::I2I(from, Integer::UInt64)); + } + Ok(SizeType::QWord) + } + + (PrimitiveType::Float(from), PrimitiveType::Integer(to)) => { + self.emit_expression_derefed(*expr.expr)?; + self.instructions.push(Instruction::F2I(from, to)); + Ok(SizeType::from_size(to.sizeof())) + } + (PrimitiveType::Float(from), PrimitiveType::Float(to)) => { + self.emit_expression_derefed(*expr.expr)?; + if from != to { + self.instructions.push(Instruction::F2F(from, to)); + } + Ok(SizeType::from_size(to.sizeof())) + } + + (PrimitiveType::Pointer(_), PrimitiveType::Integer(to)) => { + self.emit_expression_derefed(*expr.expr)?; + let to_size = to.sizeof(); + if 64 != to_size { + self.instructions + .push(Instruction::I2I(Integer::UInt64, to)); + } + Ok(SizeType::from_size(to_size)) + } + (PrimitiveType::Pointer(_), PrimitiveType::Pointer(_)) => { + self.emit_expression_derefed(*expr.expr)?; + // do nothing + Ok(SizeType::QWord) + } + + (PrimitiveType::Array(_), PrimitiveType::Pointer(_)) => { + self.emit_expression(*expr.expr)?; + // do nothing + Ok(SizeType::QWord) + } + (PrimitiveType::Array(_), PrimitiveType::Integer(to)) => { + self.emit_expression(*expr.expr)?; + let to_size = to.sizeof(); + if 64 != to_size { + self.instructions + .push(Instruction::I2I(Integer::UInt64, to)); + } + Ok(SizeType::from_size(to_size)) + } + _ => unreachable!("emit_expression_cast"), + } + } + fn emit_expression_member(&mut self, expr: ast2::ExprMember) -> Result { + debug_assert!(expr.src.is_address()); + self.emit_expression(*expr.src)?; + self.instructions.push(Instruction::AddI( + SizeType::QWord, + Operand::Register(0), + Operand::Constant(expr.member_offset as u64), + Operand::Register(0), + )); + Ok(SizeType::QWord) + } + fn emit_expression_arrow(&mut self, expr: ast2::ExprMember) -> Result { + // expr must be pointer + self.emit_expression_derefed(*expr.src)?; + self.instructions.push(Instruction::AddI( + SizeType::QWord, + Operand::Register(0), + Operand::Constant(expr.member_offset as u64), + Operand::Register(0), + )); + Ok(SizeType::QWord) + } + fn emit_expression_paren(&mut self, expr: ast2::ExprParen) -> Result { + unimplemented!("emit_expression_paren") + } + fn emit_expression_bracket( + &mut self, + expr: ast2::ExprBracket, + ) -> Result { + unreachable!("emit_expression_bracket"); + } + fn emit_expression_unary(&mut self, expr: ast2::ExprUnary) -> Result { + match expr.op { + ExprUnaryOp::AddressOf => { + self.emit_expression(*expr.expr) + // nothing + } + ExprUnaryOp::BitwiseNot => { + let size = self.emit_expression_derefed(*expr.expr)?; + self.instructions + .push(Instruction::BitNot(size, Operand::Register(0))); + Ok(size) + } + ExprUnaryOp::DecrementPost => { + let type_ = expr.expr.cv_type()?.type_; + let dec_amount = match &type_ { + PrimitiveType::Integer(_) => 1, + PrimitiveType::Pointer(p) => p.sizeof()?, + _ => unreachable!("emit_expression_unary: DecrementPost"), + }; + let size = SizeType::from_size(type_.sizeof()?); + self.emit_expression(*expr.expr)?; + self.instructions.push(Instruction::Move( + SizeType::QWord, + Operand::Register(0), + Operand::Register(2), + )); + self.instructions.push(Instruction::Move( + size, + Operand::Deref(0), + Operand::Register(0), + )); + self.instructions.push(Instruction::SubI( + size, + Operand::Deref(2), + Operand::Constant(dec_amount as u64), + Operand::Deref(2), + )); + Ok(size) + } + ExprUnaryOp::DecrementPre => { + let type_ = expr.expr.cv_type()?.type_; + let dec_amount = match &type_ { + PrimitiveType::Integer(_) => 1, + PrimitiveType::Pointer(p) => p.sizeof()?, + _ => unreachable!("emit_expression_unary: DecrementPre"), + }; + let size = SizeType::from_size(type_.sizeof()?); + self.emit_expression(*expr.expr)?; + self.instructions.push(Instruction::SubI( + size, + Operand::Deref(0), + Operand::Constant(dec_amount as u64), + Operand::Deref(0), + )); + Ok(SizeType::QWord) + } + ExprUnaryOp::IncrementPost => { + let type_ = expr.expr.cv_type()?.type_; + let inc_amount = match &type_ { + PrimitiveType::Integer(_) => 1, + PrimitiveType::Pointer(p) => p.sizeof()?, + _ => unreachable!("emit_expression_unary: IncrementPost"), + }; + let size = SizeType::from_size(type_.sizeof()?); + self.emit_expression(*expr.expr)?; + self.instructions.push(Instruction::Move( + SizeType::QWord, + Operand::Register(0), + Operand::Register(2), + )); + self.instructions.push(Instruction::Move( + size, + Operand::Deref(0), + Operand::Register(0), + )); + self.instructions.push(Instruction::AddI( + size, + Operand::Deref(2), + Operand::Constant(inc_amount as u64), + Operand::Deref(2), + )); + Ok(size) + } + ExprUnaryOp::IncrementPre => { + let type_ = expr.expr.cv_type()?.type_; + let dec_amount = match &type_ { + PrimitiveType::Integer(_) => 1, + PrimitiveType::Pointer(p) => p.sizeof()?, + _ => unreachable!("emit_expression_unary: IncrementPre"), + }; + let size = SizeType::from_size(type_.sizeof()?); + self.emit_expression(*expr.expr)?; + self.instructions.push(Instruction::AddI( + size, + Operand::Deref(0), + Operand::Constant(dec_amount as u64), + Operand::Deref(0), + )); + Ok(SizeType::QWord) + } + ExprUnaryOp::LogicalNot => { + let size = self.emit_expression_derefed(*expr.expr)?; + self.instructions.push(Instruction::LogicalNot( + size, + Operand::Register(0), + Operand::Register(0), + )); + Ok(SizeType::DWord) + } + ExprUnaryOp::Minus => { + let size = self.emit_expression_derefed(*expr.expr)?; + self.instructions + .push(Instruction::Neg(size, Operand::Register(0))); + Ok(size) + } + ExprUnaryOp::Dereference => { + self.emit_expression(*expr.expr)?; + Ok(SizeType::QWord) + } + ExprUnaryOp::Plus => { + // unary plus was filtered out by ast2 + unreachable!("emit_expression_unary: Plus") + } + } + } + fn emit_expression_binary(&mut self, expr: ast2::ExprBinary) -> Result { + match expr.op { + ExprBinaryOp::BitwiseAnd => { + let lhs = self.emit_expression_derefed(*expr.lhs)?; + self.instructions + .push(Instruction::Push(lhs, Operand::Register(0))); + let rhs = self.emit_expression_derefed(*expr.rhs)?; + debug_assert!(lhs == rhs); + self.instructions + .push(Instruction::Pop(lhs, Operand::Register(2))); + self.instructions.push(Instruction::BitAnd( + lhs, + Operand::Register(0), + Operand::Register(2), + )); + Ok(lhs) + } + ExprBinaryOp::BitwiseOr => { + let lhs = self.emit_expression_derefed(*expr.lhs)?; + self.instructions + .push(Instruction::Push(lhs, Operand::Register(0))); + let rhs = self.emit_expression_derefed(*expr.rhs)?; + debug_assert!(lhs == rhs); + self.instructions + .push(Instruction::Pop(lhs, Operand::Register(2))); + self.instructions.push(Instruction::BitOr( + lhs, + Operand::Register(0), + Operand::Register(2), + )); + Ok(lhs) + } + ExprBinaryOp::BitwiseXor => { + let lhs = self.emit_expression_derefed(*expr.lhs)?; + self.instructions + .push(Instruction::Push(lhs, Operand::Register(0))); + let rhs = self.emit_expression_derefed(*expr.rhs)?; + debug_assert!(lhs == rhs); + self.instructions + .push(Instruction::Pop(lhs, Operand::Register(2))); + self.instructions.push(Instruction::BitXor( + lhs, + Operand::Register(0), + Operand::Register(2), + )); + Ok(lhs) + } + + ExprBinaryOp::BitwiseAndAssign => { + self.emit_expression(*expr.lhs)?; + self.instructions + .push(Instruction::Push(SizeType::QWord, Operand::Register(0))); + let rhs = self.emit_expression_derefed(*expr.rhs)?; + self.instructions.push(Instruction::Move( + rhs, + Operand::Register(0), + Operand::Register(2), + )); + self.instructions + .push(Instruction::Pop(SizeType::QWord, Operand::Register(0))); + self.instructions.push(Instruction::BitAnd( + rhs, + Operand::Deref(0), + Operand::Register(2), + )); + Ok(SizeType::QWord) + } + ExprBinaryOp::BitwiseOrAssign => { + self.emit_expression(*expr.lhs)?; + self.instructions + .push(Instruction::Push(SizeType::QWord, Operand::Register(0))); + let rhs = self.emit_expression_derefed(*expr.rhs)?; + self.instructions.push(Instruction::Move( + rhs, + Operand::Register(0), + Operand::Register(2), + )); + self.instructions + .push(Instruction::Pop(SizeType::QWord, Operand::Register(0))); + self.instructions.push(Instruction::BitOr( + rhs, + Operand::Deref(0), + Operand::Register(2), + )); + Ok(SizeType::QWord) + } + + ExprBinaryOp::BitwiseXorAssign => { + self.emit_expression(*expr.lhs)?; + self.instructions + .push(Instruction::Push(SizeType::QWord, Operand::Register(0))); + let rhs = self.emit_expression_derefed(*expr.rhs)?; + self.instructions.push(Instruction::Move( + rhs, + Operand::Register(0), + Operand::Register(2), + )); + self.instructions + .push(Instruction::Pop(SizeType::QWord, Operand::Register(0))); + self.instructions.push(Instruction::BitXor( + rhs, + Operand::Deref(0), + Operand::Register(2), + )); + Ok(SizeType::QWord) + } + + ExprBinaryOp::ShiftLeft => { + let lhs_type = match expr.lhs.cv_type()?.type_ { + PrimitiveType::Integer(i) => i, + _ => unreachable!("emit_expression_binary: ShiftLeft"), + }; + let lhs = self.emit_expression_derefed(*expr.lhs)?; + self.instructions + .push(Instruction::Push(lhs, Operand::Register(0))); + self.emit_expression_derefed(*expr.rhs)?; + self.instructions + .push(Instruction::Pop(lhs, Operand::Register(2))); + if lhs_type.is_signed() { + self.instructions.push(Instruction::ShiftLeftI( + lhs, + Operand::Register(2), + Operand::Register(0), + )); + } else { + self.instructions.push(Instruction::ShiftLeftU( + lhs, + Operand::Register(2), + Operand::Register(0), + )); + } + self.instructions.push(Instruction::Move( + lhs, + Operand::Register(2), + Operand::Register(0), + )); + Ok(lhs) + } + + ExprBinaryOp::ShiftRight => { + let lhs_type = match expr.lhs.cv_type()?.type_ { + PrimitiveType::Integer(i) => i, + _ => unreachable!("emit_expression_binary: ShiftLeft"), + }; + let lhs = self.emit_expression_derefed(*expr.lhs)?; + self.instructions + .push(Instruction::Push(lhs, Operand::Register(0))); + self.emit_expression_derefed(*expr.rhs)?; + self.instructions + .push(Instruction::Pop(lhs, Operand::Register(2))); + if lhs_type.is_signed() { + self.instructions.push(Instruction::ShiftRightI( + lhs, + Operand::Register(2), + Operand::Register(0), + )); + } else { + self.instructions.push(Instruction::ShiftRightU( + lhs, + Operand::Register(2), + Operand::Register(0), + )); + } + self.instructions.push(Instruction::Move( + lhs, + Operand::Register(2), + Operand::Register(0), + )); + Ok(lhs) + } + + ExprBinaryOp::ShiftLeftAssign => { + let lhs_type = match expr.lhs.cv_type()?.type_ { + PrimitiveType::Integer(i) => i, + _ => unreachable!("emit_expression_binary: ShiftLeft"), + }; + let lhs_size = SizeType::from_size(lhs_type.sizeof()); + self.emit_expression(*expr.lhs)?; + self.instructions + .push(Instruction::Push(SizeType::QWord, Operand::Register(0))); + self.emit_expression_derefed(*expr.rhs)?; + self.instructions + .push(Instruction::Pop(SizeType::QWord, Operand::Register(2))); + if lhs_type.is_signed() { + self.instructions.push(Instruction::ShiftRightI( + lhs_size, + Operand::Deref(2), + Operand::Register(0), + )); + } else { + self.instructions.push(Instruction::ShiftRightU( + lhs_size, + Operand::Deref(2), + Operand::Register(0), + )); + } + self.instructions.push(Instruction::Move( + SizeType::QWord, + Operand::Register(2), + Operand::Register(0), + )); + Ok(SizeType::QWord) + } + + ExprBinaryOp::ShiftRightAssign => { + let lhs_type = match expr.lhs.cv_type()?.type_ { + PrimitiveType::Integer(i) => i, + _ => unreachable!("emit_expression_binary: ShiftLeft"), + }; + let lhs_size = SizeType::from_size(lhs_type.sizeof()); + self.emit_expression(*expr.lhs)?; + self.instructions + .push(Instruction::Push(SizeType::QWord, Operand::Register(0))); + self.emit_expression_derefed(*expr.rhs)?; + self.instructions + .push(Instruction::Pop(SizeType::QWord, Operand::Register(2))); + if lhs_type.is_signed() { + self.instructions.push(Instruction::ShiftRightI( + lhs_size, + Operand::Deref(2), + Operand::Register(0), + )); + } else { + self.instructions.push(Instruction::ShiftRightU( + lhs_size, + Operand::Deref(2), + Operand::Register(0), + )); + } + self.instructions.push(Instruction::Move( + SizeType::QWord, + Operand::Register(2), + Operand::Register(0), + )); + Ok(SizeType::QWord) + } + + ExprBinaryOp::LogicalAnd => { + let lhs_type = expr.lhs.cv_type()?.type_; + let rhs_type = expr.rhs.cv_type()?.type_; + + let end_label = self.generate_label(); + let false_label = self.generate_label(); + + let lhs_size = match lhs_type { + PrimitiveType::Integer(_) | PrimitiveType::Pointer(_) => { + self.emit_expression_derefed(*expr.lhs)? + } + PrimitiveType::Array(_) => self.emit_expression(*expr.lhs)?, + _ => unreachable!("emit_expression_binary: {:?}", lhs_type), + }; + self.instructions.push(Instruction::JumpZero( + lhs_size, + Operand::Register(0), + false_label, + )); + + let rhs_size = match rhs_type { + PrimitiveType::Integer(_) | PrimitiveType::Pointer(_) => { + self.emit_expression_derefed(*expr.rhs)? + } + PrimitiveType::Array(_) => self.emit_expression(*expr.rhs)?, + _ => unreachable!("emit_expression_binary: {:?}", rhs_type), + }; + self.instructions.push(Instruction::JumpZero( + rhs_size, + Operand::Register(0), + false_label, + )); + self.instructions.push(Instruction::Move( + SizeType::DWord, + Operand::Constant(1), + Operand::Register(0), + )); + self.instructions.push(Instruction::Jump(end_label)); + + self.set_label(false_label); + self.instructions.push(Instruction::Move( + SizeType::DWord, + Operand::Constant(0), + Operand::Register(0), + )); + self.set_label(end_label); + + Ok(SizeType::DWord) + } + + ExprBinaryOp::LogicalOr => { + let lhs_type = expr.lhs.cv_type()?.type_; + let rhs_type = expr.rhs.cv_type()?.type_; + + let end_label = self.generate_label(); + let true_label = self.generate_label(); + + let lhs_size = match lhs_type { + PrimitiveType::Integer(_) | PrimitiveType::Pointer(_) => { + self.emit_expression_derefed(*expr.lhs)? + } + PrimitiveType::Array(_) => self.emit_expression(*expr.lhs)?, + _ => unreachable!("emit_expression_binary: {:?}", lhs_type), + }; + self.instructions.push(Instruction::JumpNotZero( + lhs_size, + Operand::Register(0), + true_label, + )); + + let rhs_size = match rhs_type { + PrimitiveType::Integer(_) | PrimitiveType::Pointer(_) => { + self.emit_expression_derefed(*expr.rhs)? + } + PrimitiveType::Array(_) => self.emit_expression(*expr.rhs)?, + _ => unreachable!("emit_expression_binary: {:?}", rhs_type), + }; + self.instructions.push(Instruction::JumpNotZero( + rhs_size, + Operand::Register(0), + true_label, + )); + self.instructions.push(Instruction::Move( + SizeType::DWord, + Operand::Constant(0), + Operand::Register(0), + )); + self.instructions.push(Instruction::Jump(end_label)); + + self.set_label(true_label); + self.instructions.push(Instruction::Move( + SizeType::DWord, + Operand::Constant(1), + Operand::Register(0), + )); + self.set_label(end_label); + + Ok(SizeType::DWord) + } + + ExprBinaryOp::Comma => { + self.emit_expression(*expr.lhs)?; + self.emit_expression(*expr.rhs) + } + + ExprBinaryOp::Assign => { + let lhs_type_size = expr.lhs.cv_type()?.type_.sizeof()?; + if expr.rhs.is_address() { + self.emit_expression(*expr.rhs)?; + self.instructions + .push(Instruction::Push(SizeType::QWord, Operand::Register(0))); + self.emit_expression(*expr.lhs)?; + self.instructions + .push(Instruction::Pop(SizeType::QWord, Operand::Register(2))); + self.instructions.push(Instruction::Memcpy( + lhs_type_size, + Operand::Register(0), + Operand::Register(2), + )); + Ok(SizeType::QWord) + } else { + let rhs = self.emit_expression(*expr.rhs)?; + self.instructions + .push(Instruction::Push(rhs, Operand::Register(0))); + self.emit_expression(*expr.lhs)?; + self.instructions + .push(Instruction::Pop(rhs, Operand::Deref(0))); + Ok(SizeType::QWord) + } + } + + ExprBinaryOp::Equal => { + let lhs = self.emit_expression_derefed(*expr.lhs)?; + self.instructions + .push(Instruction::Push(lhs, Operand::Register(0))); + let rhs = self.emit_expression_derefed(*expr.rhs)?; + debug_assert!(lhs == rhs); + self.instructions + .push(Instruction::Pop(lhs, Operand::Register(2))); + self.instructions.push(Instruction::Equal( + lhs, + Operand::Register(0), + Operand::Register(2), + Operand::Register(0), + )); + Ok(SizeType::DWord) + } + ExprBinaryOp::NotEqual => { + let lhs = self.emit_expression_derefed(*expr.lhs)?; + self.instructions + .push(Instruction::Push(lhs, Operand::Register(0))); + let rhs = self.emit_expression_derefed(*expr.rhs)?; + debug_assert!(lhs == rhs); + self.instructions + .push(Instruction::Pop(lhs, Operand::Register(2))); + self.instructions.push(Instruction::Equal( + lhs, + Operand::Register(0), + Operand::Register(2), + Operand::Register(0), + )); + self.instructions.push(Instruction::LogicalNot( + SizeType::DWord, + Operand::Register(0), + Operand::Register(0), + )); + Ok(SizeType::DWord) + } + + ExprBinaryOp::LessThan => { + let type_ = expr.lhs.cv_type()?.type_; + let lhs = self.emit_expression_derefed(*expr.lhs)?; + self.instructions + .push(Instruction::Push(lhs, Operand::Register(0))); + let rhs = self.emit_expression_derefed(*expr.rhs)?; + debug_assert!(lhs == rhs); + self.instructions + .push(Instruction::Pop(lhs, Operand::Register(2))); + // register2 = lhs + // register0 = rhs + match type_ { + PrimitiveType::Float(_) => { + self.instructions.push(Instruction::LessThanF( + rhs, + Operand::Register(2), + Operand::Register(0), + Operand::Register(0), + )); + } + PrimitiveType::Integer(i) => { + if i.is_signed() { + self.instructions.push(Instruction::LessThanI( + lhs, + Operand::Register(2), + Operand::Register(0), + Operand::Register(0), + )); + } else { + self.instructions.push(Instruction::LessThanU( + lhs, + Operand::Register(2), + Operand::Register(0), + Operand::Register(0), + )); + } + } + _ => { + self.instructions.push(Instruction::LessThanU( + lhs, + Operand::Register(2), + Operand::Register(0), + Operand::Register(0), + )); + } + } + Ok(SizeType::DWord) + } + + ExprBinaryOp::LessThanOrEqual => { + let type_ = expr.lhs.cv_type()?.type_; + let lhs = self.emit_expression_derefed(*expr.lhs)?; + self.instructions + .push(Instruction::Push(lhs, Operand::Register(0))); + let rhs = self.emit_expression_derefed(*expr.rhs)?; + debug_assert!(lhs == rhs); + self.instructions + .push(Instruction::Pop(lhs, Operand::Register(2))); + // register2 = lhs + // register0 = rhs + match type_ { + PrimitiveType::Float(_) => { + self.instructions.push(Instruction::LessThanF( + rhs, + Operand::Register(0), + Operand::Register(2), + Operand::Register(0), + )); + } + PrimitiveType::Integer(i) => { + if i.is_signed() { + self.instructions.push(Instruction::LessThanI( + lhs, + Operand::Register(0), + Operand::Register(2), + Operand::Register(0), + )); + } else { + self.instructions.push(Instruction::LessThanU( + lhs, + Operand::Register(0), + Operand::Register(2), + Operand::Register(0), + )); + } + } + _ => { + self.instructions.push(Instruction::LessThanU( + lhs, + Operand::Register(0), + Operand::Register(2), + Operand::Register(0), + )); + } + } + self.instructions.push(Instruction::LogicalNot( + SizeType::DWord, + Operand::Register(0), + Operand::Register(0), + )); + Ok(SizeType::DWord) + } + + ExprBinaryOp::GreaterThan => { + let type_ = expr.lhs.cv_type()?.type_; + let lhs = self.emit_expression_derefed(*expr.lhs)?; + self.instructions + .push(Instruction::Push(lhs, Operand::Register(0))); + let rhs = self.emit_expression_derefed(*expr.rhs)?; + debug_assert!(lhs == rhs); + self.instructions + .push(Instruction::Pop(lhs, Operand::Register(2))); + // register2 = lhs + // register0 = rhs + match type_ { + PrimitiveType::Float(_) => { + self.instructions.push(Instruction::LessThanF( + rhs, + Operand::Register(0), + Operand::Register(2), + Operand::Register(0), + )); + } + PrimitiveType::Integer(i) => { + if i.is_signed() { + self.instructions.push(Instruction::LessThanI( + lhs, + Operand::Register(0), + Operand::Register(2), + Operand::Register(0), + )); + } else { + self.instructions.push(Instruction::LessThanU( + lhs, + Operand::Register(0), + Operand::Register(2), + Operand::Register(0), + )); + } + } + _ => { + self.instructions.push(Instruction::LessThanU( + lhs, + Operand::Register(0), + Operand::Register(2), + Operand::Register(0), + )); + } + } + Ok(SizeType::DWord) + } + + ExprBinaryOp::GreaterThanOrEqual => { + let type_ = expr.lhs.cv_type()?.type_; + let lhs = self.emit_expression_derefed(*expr.lhs)?; + self.instructions + .push(Instruction::Push(lhs, Operand::Register(0))); + let rhs = self.emit_expression_derefed(*expr.rhs)?; + debug_assert!(lhs == rhs); + self.instructions + .push(Instruction::Pop(lhs, Operand::Register(2))); + // register2 = lhs + // register0 = rhs + match type_ { + PrimitiveType::Float(_) => { + self.instructions.push(Instruction::LessThanF( + rhs, + Operand::Register(2), + Operand::Register(0), + Operand::Register(0), + )); + } + PrimitiveType::Integer(i) => { + if i.is_signed() { + self.instructions.push(Instruction::LessThanI( + lhs, + Operand::Register(2), + Operand::Register(0), + Operand::Register(0), + )); + } else { + self.instructions.push(Instruction::LessThanU( + lhs, + Operand::Register(2), + Operand::Register(0), + Operand::Register(0), + )); + } + } + _ => { + self.instructions.push(Instruction::LessThanU( + lhs, + Operand::Register(2), + Operand::Register(0), + Operand::Register(0), + )); + } + } + self.instructions.push(Instruction::LogicalNot( + SizeType::DWord, + Operand::Register(0), + Operand::Register(0), + )); + Ok(SizeType::DWord) + } + ExprBinaryOp::Mod => { + let is_signed = match expr.lhs.cv_type()?.type_ { + PrimitiveType::Integer(i) => i.is_signed(), + _ => unreachable!("emit_expression_binary: Mod"), + }; + let lhs = self.emit_expression_derefed(*expr.lhs)?; + self.instructions + .push(Instruction::Push(lhs, Operand::Register(0))); + self.emit_expression_derefed(*expr.rhs)?; + self.instructions + .push(Instruction::Pop(lhs, Operand::Register(2))); + + if is_signed { + self.instructions.push(Instruction::ModI( + lhs, + Operand::Register(2), + Operand::Register(0), + Operand::Register(0), + )); + } else { + self.instructions.push(Instruction::ModU( + lhs, + Operand::Register(2), + Operand::Register(0), + Operand::Register(0), + )); + } + + Ok(lhs) + } + + ExprBinaryOp::Mul => { + let type_ = expr.lhs.cv_type()?.type_; + let lhs = self.emit_expression_derefed(*expr.lhs)?; + self.instructions + .push(Instruction::Push(lhs, Operand::Register(0))); + self.emit_expression_derefed(*expr.rhs)?; + self.instructions + .push(Instruction::Pop(lhs, Operand::Register(2))); + match type_ { + PrimitiveType::Integer(i) => { + if i.is_signed() { + self.instructions.push(Instruction::MulI( + lhs, + Operand::Register(2), + Operand::Register(0), + Operand::Register(0), + )); + } else { + self.instructions.push(Instruction::MulU( + lhs, + Operand::Register(2), + Operand::Register(0), + Operand::Register(0), + )); + } + } + PrimitiveType::Float(_) => { + self.instructions.push(Instruction::MulF( + lhs, + Operand::Register(2), + Operand::Register(0), + Operand::Register(0), + )); + } + _ => unreachable!("emit_expression_binary: Mul"), + } + Ok(lhs) + } + ExprBinaryOp::Div => { + let type_ = expr.lhs.cv_type()?.type_; + let lhs = self.emit_expression_derefed(*expr.lhs)?; + self.instructions + .push(Instruction::Push(lhs, Operand::Register(0))); + self.emit_expression_derefed(*expr.rhs)?; + self.instructions + .push(Instruction::Pop(lhs, Operand::Register(2))); + match type_ { + PrimitiveType::Integer(i) => { + if i.is_signed() { + self.instructions.push(Instruction::DivI( + lhs, + Operand::Register(2), + Operand::Register(0), + Operand::Register(0), + )); + } else { + self.instructions.push(Instruction::DivU( + lhs, + Operand::Register(2), + Operand::Register(0), + Operand::Register(0), + )); + } + } + PrimitiveType::Float(_) => { + self.instructions.push(Instruction::DivF( + lhs, + Operand::Register(2), + Operand::Register(0), + Operand::Register(0), + )); + } + _ => unreachable!("emit_expression_binary: Div"), + } + Ok(lhs) + } + + ExprBinaryOp::Add => { + let type_ = expr.lhs.cv_type()?.type_; + let lhs = self.emit_expression_derefed(*expr.lhs)?; + self.instructions + .push(Instruction::Push(lhs, Operand::Register(0))); + let rhs = self.emit_expression_derefed(*expr.rhs)?; + debug_assert!(lhs == rhs); + self.instructions + .push(Instruction::Pop(lhs, Operand::Register(2))); + match type_ { + PrimitiveType::Integer(_) => { + self.instructions.push(Instruction::AddI( + lhs, + Operand::Register(2), + Operand::Register(0), + Operand::Register(0), + )); + } + PrimitiveType::Float(_) => { + self.instructions.push(Instruction::AddF( + lhs, + Operand::Register(2), + Operand::Register(0), + Operand::Register(0), + )); + } + _ => unreachable!("emit_expression_binary: Add"), + } + Ok(lhs) + } + + ExprBinaryOp::Sub => { + let type_ = expr.lhs.cv_type()?.type_; + let lhs = self.emit_expression_derefed(*expr.lhs)?; + self.instructions + .push(Instruction::Push(lhs, Operand::Register(0))); + let rhs = self.emit_expression_derefed(*expr.rhs)?; + debug_assert!(lhs == rhs); + self.instructions + .push(Instruction::Pop(lhs, Operand::Register(2))); + match type_ { + PrimitiveType::Integer(_) => { + self.instructions.push(Instruction::SubI( + lhs, + Operand::Register(2), + Operand::Register(0), + Operand::Register(0), + )); + } + PrimitiveType::Float(_) => { + self.instructions.push(Instruction::SubF( + lhs, + Operand::Register(2), + Operand::Register(0), + Operand::Register(0), + )); + } + _ => unreachable!("emit_expression_binary: Sub"), + } + Ok(lhs) + } + + _ => unimplemented!("emit_expression_binary: {:?}", expr.op), + } + } fn emit_expression_initializerlist( &mut self, expr: ast2::ExprInitializerList, - ) -> Result<(), CompileError> { + ) -> Result { + unimplemented!("emit_expression_initializerlist") } } diff --git a/src/virtualmachine/instruction.rs b/src/virtualmachine/instruction.rs index 0e82928..08048ac 100644 --- a/src/virtualmachine/instruction.rs +++ b/src/virtualmachine/instruction.rs @@ -1,1728 +1,67 @@ +use crate::ast2::Address; +use crate::ast2::{Float, Integer}; + use super::LabelType; +use super::Operand; +use super::SizeType; #[derive(Debug, Clone)] pub enum Instruction { - I64(i64), - U64(u64), - - /// Dereference N bytes from the address in register RAX. - /// Put the value in register RAX. - Deref(usize), + /// from -> to + Move(SizeType, Operand, Operand), Jump(LabelType), - JumpZero(usize, LabelType), - - MoveRegister(MoveRegister), - PushStack(PushStack), - PopStack(PopStack), - Jump(Jump), - JumpNonZero(JumpNonZero), - Print(Print), - Panic(Panic), - Call(Call), - Return(Return), - PrintStr(PrintStr), - - Cast(Cast), - Negate(Negate), - LogicalNot(LogicalNot), - BitwiseNot(BitwiseNot), - LessThan(LessThan), - Equal(Equal), - AddAssign(AddAssign), - SubAssign(SubAssign), - MulAssign(MulAssign), - DivAssign(DivAssign), - ModAssign(ModAssign), - BitwiseAndAssign(BitwiseAndAssign), - BitwiseOrAssign(BitwiseOrAssign), - BitwiseXorAssign(BitwiseXorAssign), - ShiftLeftAssign(ShiftLeftAssign), - ShiftRightAssign(ShiftRightAssign), - Assign(Assign), - AssignStruct(AssignStruct), -} - -impl Instruction { - pub fn execute(&self, program: &mut VirtualMachine) { - match self { - Instruction::MoveRegister(inst) => inst.execute(program), - Instruction::PushStack(inst) => inst.execute(program), - Instruction::PopStack(inst) => inst.execute(program), - Instruction::Jump(inst) => inst.execute(program), - Instruction::JumpZero(inst) => inst.execute(program), - Instruction::JumpNonZero(inst) => inst.execute(program), - Instruction::Print(inst) => inst.execute(program), - Instruction::Panic(inst) => inst.execute(program), - Instruction::Call(inst) => inst.execute(program), - Instruction::Return(inst) => inst.execute(program), - Instruction::PrintStr(inst) => inst.execute(program), - Instruction::Cast(inst) => inst.execute(program), - Instruction::Negate(inst) => inst.execute(program), - Instruction::LogicalNot(inst) => inst.execute(program), - Instruction::BitwiseNot(inst) => inst.execute(program), - Instruction::LessThan(inst) => inst.execute(program), - Instruction::Equal(inst) => inst.execute(program), - Instruction::AddAssign(inst) => inst.execute(program), - Instruction::SubAssign(inst) => inst.execute(program), - Instruction::MulAssign(inst) => inst.execute(program), - Instruction::DivAssign(inst) => inst.execute(program), - Instruction::ModAssign(inst) => inst.execute(program), - Instruction::BitwiseAndAssign(inst) => inst.execute(program), - Instruction::BitwiseOrAssign(inst) => inst.execute(program), - Instruction::BitwiseXorAssign(inst) => inst.execute(program), - Instruction::ShiftLeftAssign(inst) => inst.execute(program), - Instruction::ShiftRightAssign(inst) => inst.execute(program), - Instruction::Assign(inst) => inst.execute(program), - Instruction::AssignStruct(inst) => inst.execute(program), - } - } -} - -/// copy register N to register M -#[derive(Debug, Clone)] -pub struct MoveRegister { - pub operand_from: Operand, - pub operand_to: Operand, -} -impl MoveRegister { - fn execute(&self, program: &mut VirtualMachine) { - let rhs = get_operand_value(program, &self.operand_from).clone(); - let lhs = get_operand_value_mut(program, &self.operand_to); - *lhs = rhs; - } -} -#[derive(Debug, Clone)] -pub struct PushStack { - pub operand: Operand, -} -impl PushStack { - fn execute(&self, program: &mut VirtualMachine) { - // check if operand is stack pointer - if let Operand::Register(reg_id) = &self.operand { - if reg_id == &STACK_POINTER_REGISTER { - panic!("Cannot push RSP"); - } - } - let value = get_operand_value(program, &self.operand).clone(); - let stack_index = program.registers[STACK_POINTER_REGISTER].to_u64() as usize; - - // overflow check - if stack_index == STACK_SIZE { - panic!("PushStack: stack overflow"); - } - - program.stack[stack_index] = value; - - // inc stack pointer - if let VariableData::UInt64(ref mut value) = program.registers[STACK_POINTER_REGISTER] { - *value += 1; - } else { - panic!("PushStack: stack pointer is not UInt64"); - } - } -} -#[derive(Debug, Clone)] -pub struct PopStack { - pub operand: Operand, -} -impl PopStack { - fn execute(&self, program: &mut VirtualMachine) { - // check if operand is stack pointer - if let Operand::Register(reg_id) = &self.operand { - if reg_id == &STACK_POINTER_REGISTER { - panic!("Cannot Pop to RSP"); - } - } - let stack_index = if let VariableData::UInt64(ref mut value) = - program.registers[STACK_POINTER_REGISTER] - { - *value -= 1; - *value - } else { - panic!("PushStack: stack pointer is not UInt64"); - }; - *get_operand_value_mut(program, &self.operand) = - program.stack[stack_index as usize].clone(); - } -} - -/// jump to address in Register N -#[derive(Debug, Clone)] -pub struct Jump { - pub label: String, -} -impl Jump { - fn execute(&self, program: &mut crate::virtualmachine::vm::VirtualMachine) { - let address = program - .label_map - .get(&self.label) - .expect(format!("Jump: label not found: {}", self.label).as_str()) - .clone(); - program.current_instruction = address; - } -} - -/// Jump to address if register N is zero -#[derive(Debug, Clone)] -pub struct JumpZero { - pub label: String, - pub operand_cond: Operand, -} -impl JumpZero { - fn execute(&self, program: &mut crate::virtualmachine::vm::VirtualMachine) { - let address = program - .label_map - .get(&self.label) - .expect(format!("JumpZero: label not found: {}", self.label).as_str()) - .clone(); - let cond = get_operand_value(program, &self.operand_cond).to_u64(); - if cond == 0 { - program.current_instruction = address; - } - } -} - -/// Jump to address if register N is not zero -#[derive(Debug, Clone)] -pub struct JumpNonZero { - pub label: String, - pub operand_cond: Operand, -} -impl JumpNonZero { - fn execute(&self, program: &mut crate::virtualmachine::vm::VirtualMachine) { - let address = program - .label_map - .get(&self.label) - .expect(format!("JumpNonZero: label not found: {}", self.label).as_str()) - .clone(); - let cond = get_operand_value(program, &self.operand_cond).to_u64(); - if cond != 0 { - program.current_instruction = address; - } - } -} - -/// print vars in stack -#[derive(Debug, Clone)] -pub struct Print {} -impl Print { - fn execute(&self, program: &mut crate::virtualmachine::vm::VirtualMachine) { - PopStack { - operand: Operand::Register(1), - } - .execute(program); - - let var_count = get_operand_value(program, &Operand::Register(1)).to_u64(); - print!("Print: "); - for _ in 0..var_count { - PopStack { - operand: Operand::Register(1), - } - .execute(program); - let var = get_operand_value(program, &Operand::Register(1)); - print!("{:?}, ", var); - } - println!(""); - } -} - -/// instruction that panic -#[derive(Debug, Clone)] -pub struct Panic { - pub message: String, -} -impl Panic { - fn execute(&self, _program: &mut crate::virtualmachine::vm::VirtualMachine) { - panic!("Panic: {}", self.message); - } -} - -/// push current address and scope count to stack and jump -#[derive(Debug, Clone)] -pub struct Call { - pub label: String, -} -impl Call { - fn execute(&self, program: &mut crate::virtualmachine::vm::VirtualMachine) { - let move_to_address = *program - .label_map - .get(&self.label) - .expect(format!("Call: label not found: {}", self.label).as_str()); - // let move_to_address = get_operand_value(program, &self.address).to_u64() as usize; - let current_address = program.current_instruction; - - // push current address to stack - PushStack { - operand: Operand::Value(VariableData::UInt64(current_address as u64)), - } - .execute(program); - - // jump to address - program.current_instruction = move_to_address; - } -} - -#[derive(Debug, Clone)] -pub struct Return {} -impl Return { - fn execute(&self, program: &mut crate::virtualmachine::vm::VirtualMachine) { - // register0 is beging used by returned value - - // current base pointer is old stack pointer - let cur_base_pointer = program.registers[STACK_POINTER_BASE_REGISTER].to_u64() as usize; - - let old_base_pointer = program.stack[cur_base_pointer - 1].to_u64() as usize; - let return_address = program.stack[cur_base_pointer - 2].to_u64() as usize; - - program.registers[STACK_POINTER_REGISTER] = - VariableData::UInt64(cur_base_pointer as u64 - 2); - program.registers[STACK_POINTER_BASE_REGISTER] = - VariableData::UInt64(old_base_pointer as u64); - program.current_instruction = return_address; - } -} - -#[derive(Debug, Clone)] -pub struct PrintStr { - pub str: Operand, // null terminated string -} -impl PrintStr { - fn execute(&self, program: &mut crate::virtualmachine::vm::VirtualMachine) { - let mut address = get_operand_value(program, &self.str).to_u64() as usize; - - let mut chars = Vec::new(); - - while program.stack[address].to_u64() != 0 { - let ch = program.stack[address].to_u64() as u8; - chars.push(ch); - address += 1; - } - let string = String::from_utf8(chars).unwrap(); - println!("{:?}", string); - } -} - -/// cast register N to type -#[derive(Debug, Clone)] -pub struct Cast { - pub info: TypeInfo, - pub operand_from: Operand, - pub operand_to: Operand, -} -impl Cast { - fn execute(&self, program: &mut VirtualMachine) { - let rhs_casted = get_operand_value(program, &self.operand_from) - .cast_to(&self.info) - .expect(format!("Invalid cast: to {:?}", &self.info).as_str()); - *get_operand_value_mut(program, &self.operand_to) = rhs_casted; - } -} - -/// neg register N -#[derive(Debug, Clone)] -pub struct Negate { - pub operand: Operand, -} -impl Negate { - fn execute(&self, program: &mut VirtualMachine) { - let var = get_operand_value_mut(program, &self.operand); - let res = match &var { - VariableData::UInt8(value) => VariableData::Int8(-(*value as i8)), - VariableData::UInt16(value) => VariableData::Int16(-(*value as i16)), - VariableData::UInt32(value) => VariableData::Int32(-(*value as i32)), - VariableData::UInt64(value) => VariableData::Int64(-(*value as i64)), - VariableData::Int8(value) => VariableData::Int8(-*value), - VariableData::Int16(value) => VariableData::Int16(-*value), - VariableData::Int32(value) => VariableData::Int32(-*value), - VariableData::Int64(value) => VariableData::Int64(-*value), - VariableData::Float32(value) => VariableData::Float32(-*value), - VariableData::Float64(value) => VariableData::Float64(-*value), - }; - *var = res; - } -} - -/// logical not register N -#[derive(Debug, Clone)] -pub struct LogicalNot { - pub operand: Operand, -} -impl LogicalNot { - fn execute(&self, program: &mut VirtualMachine) { - let var = get_operand_value_mut(program, &self.operand); - let res = match &var { - VariableData::UInt8(value) => { - if *value == 0 { - 1 - } else { - 0 - } - } - VariableData::UInt16(value) => { - if *value == 0 { - 1 - } else { - 0 - } - } - VariableData::UInt32(value) => { - if *value == 0 { - 1 - } else { - 0 - } - } - VariableData::UInt64(value) => { - if *value == 0 { - 1 - } else { - 0 - } - } - VariableData::Int8(value) => { - if *value == 0 { - 1 - } else { - 0 - } - } - VariableData::Int16(value) => { - if *value == 0 { - 1 - } else { - 0 - } - } - VariableData::Int32(value) => { - if *value == 0 { - 1 - } else { - 0 - } - } - VariableData::Int64(value) => { - if *value == 0 { - 1 - } else { - 0 - } - } - _ => panic!("Invalid type for logical not"), - }; - *var = VariableData::UInt8(res as u8); - } -} - -/// bitwise not register N -#[derive(Debug, Clone)] -pub struct BitwiseNot { - pub operand: Operand, -} -impl BitwiseNot { - fn execute(&self, program: &mut VirtualMachine) { - let var = get_operand_value_mut(program, &self.operand); - match var { - VariableData::UInt8(ref mut value) => *value = !*value, - VariableData::UInt16(ref mut value) => *value = !*value, - VariableData::UInt32(ref mut value) => *value = !*value, - VariableData::UInt64(ref mut value) => *value = !*value, - VariableData::Int8(ref mut value) => *value = !*value, - VariableData::Int16(ref mut value) => *value = !*value, - VariableData::Int32(ref mut value) => *value = !*value, - VariableData::Int64(ref mut value) => *value = !*value, - _ => panic!("Invalid type for bitwise not"), - } - } -} - -#[derive(Debug, Clone)] -pub struct LessThan { - pub lhs: Operand, - pub rhs: Operand, - pub to: Operand, -} -impl LessThan { - fn execute(&self, program: &mut VirtualMachine) { - let ret: bool = { - let lhs = get_operand_value(program, &self.lhs); - let rhs = get_operand_value(program, &self.rhs); - - if lhs.is_signed_integer() { - if rhs.is_signed_integer() { - let lhs = lhs.to_i64(); - let rhs = rhs.to_i64(); - lhs < rhs - } else if rhs.is_unsigned_integer() { - let lhs = lhs.to_i64(); - let rhs = rhs.to_u64(); - if lhs < 0 { - true - } else { - (lhs as u64) < rhs - } - } else if rhs.is_float() { - lhs.to_f64() < rhs.to_f64() - } else { - panic!("Invalid type for less than"); - } - } else if lhs.is_unsigned_integer() { - if rhs.is_signed_integer() { - let lhs = lhs.to_u64(); - let rhs = rhs.to_i64(); - if rhs < 0 { - false - } else { - lhs < rhs as u64 - } - } else if rhs.is_unsigned_integer() { - let lhs = lhs.to_u64(); - let rhs = rhs.to_u64(); - lhs < rhs - } else if rhs.is_float() { - lhs.to_f64() < rhs.to_f64() - } else { - panic!("Invalid type for less than"); - } - } else if lhs.is_float() { - lhs.to_f64() < rhs.to_f64() - } else { - panic!("Invalid type for less than"); - } - }; - *get_operand_value_mut(program, &self.to) = VariableData::UInt8(if ret { 1 } else { 0 }); - } -} - -#[derive(Debug, Clone)] -pub struct Equal { - pub lhs: Operand, - pub rhs: Operand, - pub to: Operand, -} -impl Equal { - fn execute(&self, program: &mut VirtualMachine) { - let ret: bool = { - let lhs = get_operand_value(program, &self.lhs); - let rhs = get_operand_value(program, &self.rhs); - - if lhs.is_signed_integer() { - let lhs = lhs.to_i64(); - if rhs.is_signed_integer() { - let rhs = rhs.to_i64(); - lhs == rhs - } else if rhs.is_unsigned_integer() { - let rhs = rhs.to_u64(); - if lhs < 0 { - false - } else { - (lhs as u64) == rhs - } - } else if rhs.is_float() { - panic!("floating point variables are not equal-comparable"); - } else { - panic!("Invalid type for equal"); - } - } else if lhs.is_unsigned_integer() { - let lhs = lhs.to_u64(); - if rhs.is_signed_integer() { - let rhs = rhs.to_i64(); - if rhs < 0 { - false - } else { - lhs == rhs as u64 - } - } else if rhs.is_unsigned_integer() { - let rhs = rhs.to_u64(); - lhs == rhs - } else if rhs.is_float() { - panic!("floating point variables are not equal-comparable"); - } else { - panic!("Invalid type for equal"); - } - } else if lhs.is_float() { - panic!("floating point variables are not equal-comparable"); - } else { - panic!("Invalid type for equal"); - } - }; - *get_operand_value_mut(program, &self.to) = VariableData::UInt8(if ret { 1 } else { 0 }); - } -} - -#[derive(Debug, Clone)] -pub struct AddAssign { - pub lhs: Operand, - pub rhs: Operand, -} -impl AddAssign { - fn execute(&self, program: &mut VirtualMachine) { - let rhs = get_operand_value(program, &self.rhs).clone(); - let lhs = get_operand_value_mut(program, &self.lhs); - match lhs { - VariableData::UInt8(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_add(rhs).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_add(rhs as u8).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_add(rhs as u8).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_add(rhs as u8).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_add_signed(rhs).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_add_signed(rhs as i8).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_add_signed(rhs as i8).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_add_signed(rhs as i8).0, - _ => panic!("Invalid type for add assign"), - }, - VariableData::UInt16(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_add(rhs as u16).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_add(rhs as u16).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_add(rhs as u16).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_add(rhs as u16).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_add_signed(rhs as i16).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_add_signed(rhs as i16).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_add_signed(rhs as i16).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_add_signed(rhs as i16).0, - _ => panic!("Invalid type for add assign"), - }, - VariableData::UInt32(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_add(rhs as u32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_add(rhs as u32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_add(rhs as u32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_add(rhs as u32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_add_signed(rhs as i32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_add_signed(rhs as i32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_add_signed(rhs as i32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_add_signed(rhs as i32).0, - _ => panic!("Invalid type for add assign"), - }, - VariableData::UInt64(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_add(rhs as u64).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_add(rhs as u64).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_add(rhs as u64).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_add(rhs as u64).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_add_signed(rhs as i64).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_add_signed(rhs as i64).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_add_signed(rhs as i64).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_add_signed(rhs as i64).0, - _ => panic!("Invalid type for add assign"), - }, - - VariableData::Int8(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_add_unsigned(rhs as u8).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_add_unsigned(rhs as u8).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_add_unsigned(rhs as u8).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_add_unsigned(rhs as u8).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_add(rhs as i8).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_add(rhs as i8).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_add(rhs as i8).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_add(rhs as i8).0, - _ => panic!("Invalid type for add assign"), - }, - - VariableData::Int16(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_add_unsigned(rhs as u16).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_add_unsigned(rhs as u16).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_add_unsigned(rhs as u16).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_add_unsigned(rhs as u16).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_add(rhs as i16).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_add(rhs as i16).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_add(rhs as i16).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_add(rhs as i16).0, - _ => panic!("Invalid type for add assign"), - }, - VariableData::Int32(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_add_unsigned(rhs as u32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_add_unsigned(rhs as u32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_add_unsigned(rhs as u32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_add_unsigned(rhs as u32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_add(rhs as i32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_add(rhs as i32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_add(rhs as i32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_add(rhs as i32).0, - _ => panic!("Invalid type for add assign"), - }, - VariableData::Int64(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_add_unsigned(rhs as u64).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_add_unsigned(rhs as u64).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_add_unsigned(rhs as u64).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_add_unsigned(rhs as u64).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_add(rhs as i64).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_add(rhs as i64).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_add(rhs as i64).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_add(rhs as i64).0, - _ => panic!("Invalid type for add assign"), - }, - - VariableData::Float32(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs += rhs as f32, - VariableData::UInt16(rhs) => *lhs += rhs as f32, - VariableData::UInt32(rhs) => *lhs += rhs as f32, - VariableData::UInt64(rhs) => *lhs += rhs as f32, - VariableData::Int8(rhs) => *lhs += rhs as f32, - VariableData::Int16(rhs) => *lhs += rhs as f32, - VariableData::Int32(rhs) => *lhs += rhs as f32, - VariableData::Int64(rhs) => *lhs += rhs as f32, - VariableData::Float32(rhs) => *lhs += rhs as f32, - VariableData::Float64(rhs) => *lhs += rhs as f32, - }, - VariableData::Float64(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs += rhs as f64, - VariableData::UInt16(rhs) => *lhs += rhs as f64, - VariableData::UInt32(rhs) => *lhs += rhs as f64, - VariableData::UInt64(rhs) => *lhs += rhs as f64, - VariableData::Int8(rhs) => *lhs += rhs as f64, - VariableData::Int16(rhs) => *lhs += rhs as f64, - VariableData::Int32(rhs) => *lhs += rhs as f64, - VariableData::Int64(rhs) => *lhs += rhs as f64, - VariableData::Float32(rhs) => *lhs += rhs as f64, - VariableData::Float64(rhs) => *lhs += rhs as f64, - }, - } - } -} - -#[derive(Debug, Clone)] -pub struct SubAssign { - pub lhs: Operand, - pub rhs: Operand, -} -impl SubAssign { - fn execute(&self, program: &mut VirtualMachine) { - let rhs = get_operand_value(program, &self.rhs).clone(); - let lhs = get_operand_value_mut(program, &self.lhs); - match lhs { - VariableData::UInt8(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_sub(rhs).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_sub(rhs as u8).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_sub(rhs as u8).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_sub(rhs as u8).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_sub(rhs as u8).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_sub(rhs as u8).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_sub(rhs as u8).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_sub(rhs as u8).0, - _ => panic!("Invalid type for sub assign"), - }, - VariableData::UInt16(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_sub(rhs as u16).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_sub(rhs as u16).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_sub(rhs as u16).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_sub(rhs as u16).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_sub(rhs as u16).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_sub(rhs as u16).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_sub(rhs as u16).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_sub(rhs as u16).0, - _ => panic!("Invalid type for sub assign"), - }, - VariableData::UInt32(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_sub(rhs as u32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_sub(rhs as u32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_sub(rhs as u32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_sub(rhs as u32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_sub(rhs as u32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_sub(rhs as u32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_sub(rhs as u32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_sub(rhs as u32).0, - _ => panic!("Invalid type for sub assign"), - }, - VariableData::UInt64(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_sub(rhs as u64).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_sub(rhs as u64).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_sub(rhs as u64).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_sub(rhs as u64).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_sub(rhs as u64).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_sub(rhs as u64).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_sub(rhs as u64).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_sub(rhs as u64).0, - _ => panic!("Invalid type for sub assign"), - }, - - VariableData::Int8(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_sub_unsigned(rhs as u8).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_sub_unsigned(rhs as u8).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_sub_unsigned(rhs as u8).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_sub_unsigned(rhs as u8).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_sub(rhs as i8).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_sub(rhs as i8).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_sub(rhs as i8).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_sub(rhs as i8).0, - _ => panic!("Invalid type for sub assign"), - }, - - VariableData::Int16(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_sub_unsigned(rhs as u16).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_sub_unsigned(rhs as u16).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_sub_unsigned(rhs as u16).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_sub_unsigned(rhs as u16).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_sub(rhs as i16).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_sub(rhs as i16).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_sub(rhs as i16).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_sub(rhs as i16).0, - _ => panic!("Invalid type for sub assign"), - }, - VariableData::Int32(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_sub_unsigned(rhs as u32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_sub_unsigned(rhs as u32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_sub_unsigned(rhs as u32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_sub_unsigned(rhs as u32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_sub(rhs as i32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_sub(rhs as i32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_sub(rhs as i32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_sub(rhs as i32).0, - _ => panic!("Invalid type for sub assign"), - }, - VariableData::Int64(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_sub_unsigned(rhs as u64).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_sub_unsigned(rhs as u64).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_sub_unsigned(rhs as u64).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_sub_unsigned(rhs as u64).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_sub(rhs as i64).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_sub(rhs as i64).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_sub(rhs as i64).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_sub(rhs as i64).0, - _ => panic!("Invalid type for sub assign"), - }, - - VariableData::Float32(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs -= rhs as f32, - VariableData::UInt16(rhs) => *lhs -= rhs as f32, - VariableData::UInt32(rhs) => *lhs -= rhs as f32, - VariableData::UInt64(rhs) => *lhs -= rhs as f32, - VariableData::Int8(rhs) => *lhs -= rhs as f32, - VariableData::Int16(rhs) => *lhs -= rhs as f32, - VariableData::Int32(rhs) => *lhs -= rhs as f32, - VariableData::Int64(rhs) => *lhs -= rhs as f32, - VariableData::Float32(rhs) => *lhs -= rhs as f32, - VariableData::Float64(rhs) => *lhs -= rhs as f32, - }, - VariableData::Float64(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs -= rhs as f64, - VariableData::UInt16(rhs) => *lhs -= rhs as f64, - VariableData::UInt32(rhs) => *lhs -= rhs as f64, - VariableData::UInt64(rhs) => *lhs -= rhs as f64, - VariableData::Int8(rhs) => *lhs -= rhs as f64, - VariableData::Int16(rhs) => *lhs -= rhs as f64, - VariableData::Int32(rhs) => *lhs -= rhs as f64, - VariableData::Int64(rhs) => *lhs -= rhs as f64, - VariableData::Float32(rhs) => *lhs -= rhs as f64, - VariableData::Float64(rhs) => *lhs -= rhs as f64, - }, - } - } -} - -#[derive(Debug, Clone)] -pub struct MulAssign { - pub lhs: Operand, - pub rhs: Operand, -} -impl MulAssign { - fn execute(&self, program: &mut VirtualMachine) { - let rhs = get_operand_value(program, &self.rhs).clone(); - let lhs = get_operand_value_mut(program, &self.lhs); - - match lhs { - VariableData::UInt8(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_mul(rhs as u8).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_mul(rhs as u8).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_mul(rhs as u8).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_mul(rhs as u8).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_mul(rhs as u8).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_mul(rhs as u8).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_mul(rhs as u8).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_mul(rhs as u8).0, - _ => panic!("Invalid type for mul assign"), - }, - VariableData::UInt16(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_mul(rhs as u16).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_mul(rhs as u16).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_mul(rhs as u16).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_mul(rhs as u16).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_mul(rhs as u16).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_mul(rhs as u16).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_mul(rhs as u16).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_mul(rhs as u16).0, - _ => panic!("Invalid type for mul assign"), - }, - VariableData::UInt32(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_mul(rhs as u32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_mul(rhs as u32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_mul(rhs as u32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_mul(rhs as u32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_mul(rhs as u32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_mul(rhs as u32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_mul(rhs as u32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_mul(rhs as u32).0, - _ => panic!("Invalid type for mul assign"), - }, - VariableData::UInt64(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_mul(rhs as u64).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_mul(rhs as u64).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_mul(rhs as u64).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_mul(rhs as u64).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_mul(rhs as u64).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_mul(rhs as u64).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_mul(rhs as u64).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_mul(rhs as u64).0, - _ => panic!("Invalid type for mul assign"), - }, - VariableData::Int8(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_mul(rhs as i8).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_mul(rhs as i8).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_mul(rhs as i8).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_mul(rhs as i8).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_mul(rhs as i8).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_mul(rhs as i8).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_mul(rhs as i8).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_mul(rhs as i8).0, - _ => panic!("Invalid type for mul assign"), - }, - VariableData::Int16(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_mul(rhs as i16).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_mul(rhs as i16).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_mul(rhs as i16).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_mul(rhs as i16).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_mul(rhs as i16).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_mul(rhs as i16).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_mul(rhs as i16).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_mul(rhs as i16).0, - _ => panic!("Invalid type for mul assign"), - }, - VariableData::Int32(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_mul(rhs as i32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_mul(rhs as i32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_mul(rhs as i32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_mul(rhs as i32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_mul(rhs as i32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_mul(rhs as i32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_mul(rhs as i32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_mul(rhs as i32).0, - _ => panic!("Invalid type for mul assign"), - }, - VariableData::Int64(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_mul(rhs as i64).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_mul(rhs as i64).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_mul(rhs as i64).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_mul(rhs as i64).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_mul(rhs as i64).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_mul(rhs as i64).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_mul(rhs as i64).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_mul(rhs as i64).0, - _ => panic!("Invalid type for mul assign"), - }, - VariableData::Float32(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs *= rhs as f32, - VariableData::UInt16(rhs) => *lhs *= rhs as f32, - VariableData::UInt32(rhs) => *lhs *= rhs as f32, - VariableData::UInt64(rhs) => *lhs *= rhs as f32, - VariableData::Int8(rhs) => *lhs *= rhs as f32, - VariableData::Int16(rhs) => *lhs *= rhs as f32, - VariableData::Int32(rhs) => *lhs *= rhs as f32, - VariableData::Int64(rhs) => *lhs *= rhs as f32, - VariableData::Float32(rhs) => *lhs *= rhs as f32, - VariableData::Float64(rhs) => *lhs *= rhs as f32, - }, - VariableData::Float64(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs *= rhs as f64, - VariableData::UInt16(rhs) => *lhs *= rhs as f64, - VariableData::UInt32(rhs) => *lhs *= rhs as f64, - VariableData::UInt64(rhs) => *lhs *= rhs as f64, - VariableData::Int8(rhs) => *lhs *= rhs as f64, - VariableData::Int16(rhs) => *lhs *= rhs as f64, - VariableData::Int32(rhs) => *lhs *= rhs as f64, - VariableData::Int64(rhs) => *lhs *= rhs as f64, - VariableData::Float32(rhs) => *lhs *= rhs as f64, - VariableData::Float64(rhs) => *lhs *= rhs as f64, - }, - } - } -} - -#[derive(Debug, Clone)] -pub struct DivAssign { - pub lhs: Operand, - pub rhs: Operand, -} -impl DivAssign { - fn execute(&self, program: &mut VirtualMachine) { - let rhs = get_operand_value(program, &self.rhs).clone(); - let lhs = get_operand_value_mut(program, &self.lhs); - - match lhs { - VariableData::UInt8(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_div(rhs as u8).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_div(rhs as u8).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_div(rhs as u8).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_div(rhs as u8).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_div(rhs as u8).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_div(rhs as u8).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_div(rhs as u8).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_div(rhs as u8).0, - _ => panic!("Invalid type for div assign"), - }, - VariableData::UInt16(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_div(rhs as u16).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_div(rhs as u16).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_div(rhs as u16).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_div(rhs as u16).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_div(rhs as u16).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_div(rhs as u16).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_div(rhs as u16).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_div(rhs as u16).0, - _ => panic!("Invalid type for div assign"), - }, - VariableData::UInt32(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_div(rhs as u32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_div(rhs as u32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_div(rhs as u32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_div(rhs as u32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_div(rhs as u32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_div(rhs as u32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_div(rhs as u32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_div(rhs as u32).0, - _ => panic!("Invalid type for div assign"), - }, - VariableData::UInt64(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_div(rhs as u64).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_div(rhs as u64).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_div(rhs as u64).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_div(rhs as u64).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_div(rhs as u64).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_div(rhs as u64).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_div(rhs as u64).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_div(rhs as u64).0, - _ => panic!("Invalid type for div assign"), - }, - VariableData::Int8(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_div(rhs as i8).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_div(rhs as i8).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_div(rhs as i8).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_div(rhs as i8).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_div(rhs as i8).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_div(rhs as i8).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_div(rhs as i8).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_div(rhs as i8).0, - _ => panic!("Invalid type for div assign"), - }, - VariableData::Int16(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_div(rhs as i16).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_div(rhs as i16).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_div(rhs as i16).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_div(rhs as i16).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_div(rhs as i16).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_div(rhs as i16).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_div(rhs as i16).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_div(rhs as i16).0, - _ => panic!("Invalid type for div assign"), - }, - VariableData::Int32(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_div(rhs as i32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_div(rhs as i32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_div(rhs as i32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_div(rhs as i32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_div(rhs as i32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_div(rhs as i32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_div(rhs as i32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_div(rhs as i32).0, - _ => panic!("Invalid type for div assign"), - }, - VariableData::Int64(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_div(rhs as i64).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_div(rhs as i64).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_div(rhs as i64).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_div(rhs as i64).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_div(rhs as i64).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_div(rhs as i64).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_div(rhs as i64).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_div(rhs as i64).0, - _ => panic!("Invalid type for div assign"), - }, - VariableData::Float32(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs /= rhs as f32, - VariableData::UInt16(rhs) => *lhs /= rhs as f32, - VariableData::UInt32(rhs) => *lhs /= rhs as f32, - VariableData::UInt64(rhs) => *lhs /= rhs as f32, - VariableData::Int8(rhs) => *lhs /= rhs as f32, - VariableData::Int16(rhs) => *lhs /= rhs as f32, - VariableData::Int32(rhs) => *lhs /= rhs as f32, - VariableData::Int64(rhs) => *lhs /= rhs as f32, - VariableData::Float32(rhs) => *lhs /= rhs as f32, - VariableData::Float64(rhs) => *lhs /= rhs as f32, - }, - VariableData::Float64(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs /= rhs as f64, - VariableData::UInt16(rhs) => *lhs /= rhs as f64, - VariableData::UInt32(rhs) => *lhs /= rhs as f64, - VariableData::UInt64(rhs) => *lhs /= rhs as f64, - VariableData::Int8(rhs) => *lhs /= rhs as f64, - VariableData::Int16(rhs) => *lhs /= rhs as f64, - VariableData::Int32(rhs) => *lhs /= rhs as f64, - VariableData::Int64(rhs) => *lhs /= rhs as f64, - VariableData::Float32(rhs) => *lhs /= rhs as f64, - VariableData::Float64(rhs) => *lhs /= rhs as f64, - }, - } - } -} - -#[derive(Debug, Clone)] -pub struct ModAssign { - pub lhs: Operand, - pub rhs: Operand, -} -impl ModAssign { - fn execute(&self, program: &mut VirtualMachine) { - let rhs = get_operand_value(program, &self.rhs).clone(); - let lhs = get_operand_value_mut(program, &self.lhs); - - match lhs { - VariableData::UInt8(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_rem(rhs as u8).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_rem(rhs as u8).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_rem(rhs as u8).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_rem(rhs as u8).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_rem(rhs as u8).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_rem(rhs as u8).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_rem(rhs as u8).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_rem(rhs as u8).0, - _ => panic!("Invalid type for mod assign"), - }, - VariableData::UInt16(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_rem(rhs as u16).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_rem(rhs as u16).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_rem(rhs as u16).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_rem(rhs as u16).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_rem(rhs as u16).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_rem(rhs as u16).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_rem(rhs as u16).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_rem(rhs as u16).0, - _ => panic!("Invalid type for mod assign"), - }, - VariableData::UInt32(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_rem(rhs as u32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_rem(rhs as u32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_rem(rhs as u32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_rem(rhs as u32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_rem(rhs as u32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_rem(rhs as u32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_rem(rhs as u32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_rem(rhs as u32).0, - _ => panic!("Invalid type for mod assign"), - }, - VariableData::UInt64(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_rem(rhs as u64).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_rem(rhs as u64).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_rem(rhs as u64).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_rem(rhs as u64).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_rem(rhs as u64).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_rem(rhs as u64).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_rem(rhs as u64).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_rem(rhs as u64).0, - _ => panic!("Invalid type for mod assign"), - }, - VariableData::Int8(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_rem(rhs as i8).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_rem(rhs as i8).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_rem(rhs as i8).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_rem(rhs as i8).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_rem(rhs as i8).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_rem(rhs as i8).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_rem(rhs as i8).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_rem(rhs as i8).0, - _ => panic!("Invalid type for mod assign"), - }, - VariableData::Int16(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_rem(rhs as i16).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_rem(rhs as i16).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_rem(rhs as i16).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_rem(rhs as i16).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_rem(rhs as i16).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_rem(rhs as i16).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_rem(rhs as i16).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_rem(rhs as i16).0, - _ => panic!("Invalid type for mod assign"), - }, - VariableData::Int32(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_rem(rhs as i32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_rem(rhs as i32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_rem(rhs as i32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_rem(rhs as i32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_rem(rhs as i32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_rem(rhs as i32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_rem(rhs as i32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_rem(rhs as i32).0, - _ => panic!("Invalid type for mod assign"), - }, - VariableData::Int64(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_rem(rhs as i64).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_rem(rhs as i64).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_rem(rhs as i64).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_rem(rhs as i64).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_rem(rhs as i64).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_rem(rhs as i64).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_rem(rhs as i64).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_rem(rhs as i64).0, - _ => panic!("Invalid type for mod assign"), - }, - _ => panic!("Invalid type for mod assign"), - } - } -} - -#[derive(Debug, Clone)] -pub struct BitwiseAndAssign { - pub lhs: Operand, - pub rhs: Operand, -} -impl BitwiseAndAssign { - fn execute(&self, program: &mut VirtualMachine) { - let rhs = get_operand_value(program, &self.rhs).clone(); - let lhs = get_operand_value_mut(program, &self.lhs); - - match lhs { - VariableData::UInt8(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs &= rhs as u8, - VariableData::UInt16(rhs) => *lhs &= rhs as u8, - VariableData::UInt32(rhs) => *lhs &= rhs as u8, - VariableData::UInt64(rhs) => *lhs &= rhs as u8, - VariableData::Int8(rhs) => *lhs &= rhs as u8, - VariableData::Int16(rhs) => *lhs &= rhs as u8, - VariableData::Int32(rhs) => *lhs &= rhs as u8, - VariableData::Int64(rhs) => *lhs &= rhs as u8, - _ => panic!("Invalid type for bitwise and assign"), - }, - VariableData::UInt16(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs &= rhs as u16, - VariableData::UInt16(rhs) => *lhs &= rhs as u16, - VariableData::UInt32(rhs) => *lhs &= rhs as u16, - VariableData::UInt64(rhs) => *lhs &= rhs as u16, - VariableData::Int8(rhs) => *lhs &= rhs as u16, - VariableData::Int16(rhs) => *lhs &= rhs as u16, - VariableData::Int32(rhs) => *lhs &= rhs as u16, - VariableData::Int64(rhs) => *lhs &= rhs as u16, - _ => panic!("Invalid type for bitwise and assign"), - }, - VariableData::UInt32(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs &= rhs as u32, - VariableData::UInt16(rhs) => *lhs &= rhs as u32, - VariableData::UInt32(rhs) => *lhs &= rhs as u32, - VariableData::UInt64(rhs) => *lhs &= rhs as u32, - VariableData::Int8(rhs) => *lhs &= rhs as u32, - VariableData::Int16(rhs) => *lhs &= rhs as u32, - VariableData::Int32(rhs) => *lhs &= rhs as u32, - VariableData::Int64(rhs) => *lhs &= rhs as u32, - _ => panic!("Invalid type for bitwise and assign"), - }, - VariableData::UInt64(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs &= rhs as u64, - VariableData::UInt16(rhs) => *lhs &= rhs as u64, - VariableData::UInt32(rhs) => *lhs &= rhs as u64, - VariableData::UInt64(rhs) => *lhs &= rhs as u64, - VariableData::Int8(rhs) => *lhs &= rhs as u64, - VariableData::Int16(rhs) => *lhs &= rhs as u64, - VariableData::Int32(rhs) => *lhs &= rhs as u64, - VariableData::Int64(rhs) => *lhs &= rhs as u64, - _ => panic!("Invalid type for bitwise and assign"), - }, - - VariableData::Int8(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs &= rhs as i8, - VariableData::UInt16(rhs) => *lhs &= rhs as i8, - VariableData::UInt32(rhs) => *lhs &= rhs as i8, - VariableData::UInt64(rhs) => *lhs &= rhs as i8, - VariableData::Int8(rhs) => *lhs &= rhs as i8, - VariableData::Int16(rhs) => *lhs &= rhs as i8, - VariableData::Int32(rhs) => *lhs &= rhs as i8, - VariableData::Int64(rhs) => *lhs &= rhs as i8, - _ => panic!("Invalid type for bitwise and assign"), - }, - VariableData::Int16(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs &= rhs as i16, - VariableData::UInt16(rhs) => *lhs &= rhs as i16, - VariableData::UInt32(rhs) => *lhs &= rhs as i16, - VariableData::UInt64(rhs) => *lhs &= rhs as i16, - VariableData::Int8(rhs) => *lhs &= rhs as i16, - VariableData::Int16(rhs) => *lhs &= rhs as i16, - VariableData::Int32(rhs) => *lhs &= rhs as i16, - VariableData::Int64(rhs) => *lhs &= rhs as i16, - _ => panic!("Invalid type for bitwise and assign"), - }, - VariableData::Int32(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs &= rhs as i32, - VariableData::UInt16(rhs) => *lhs &= rhs as i32, - VariableData::UInt32(rhs) => *lhs &= rhs as i32, - VariableData::UInt64(rhs) => *lhs &= rhs as i32, - VariableData::Int8(rhs) => *lhs &= rhs as i32, - VariableData::Int16(rhs) => *lhs &= rhs as i32, - VariableData::Int32(rhs) => *lhs &= rhs as i32, - VariableData::Int64(rhs) => *lhs &= rhs as i32, - _ => panic!("Invalid type for bitwise and assign"), - }, - VariableData::Int64(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs &= rhs as i64, - VariableData::UInt16(rhs) => *lhs &= rhs as i64, - VariableData::UInt32(rhs) => *lhs &= rhs as i64, - VariableData::UInt64(rhs) => *lhs &= rhs as i64, - VariableData::Int8(rhs) => *lhs &= rhs as i64, - VariableData::Int16(rhs) => *lhs &= rhs as i64, - VariableData::Int32(rhs) => *lhs &= rhs as i64, - VariableData::Int64(rhs) => *lhs &= rhs as i64, - _ => panic!("Invalid type for bitwise and assign"), - }, - - _ => panic!("Invalid type for bitwise and assign"), - } - } -} - -#[derive(Debug, Clone)] -pub struct BitwiseOrAssign { - pub lhs: Operand, - pub rhs: Operand, -} -impl BitwiseOrAssign { - fn execute(&self, program: &mut VirtualMachine) { - let rhs = get_operand_value(program, &self.rhs).clone(); - let lhs = get_operand_value_mut(program, &self.lhs); - - match lhs { - VariableData::UInt8(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs |= rhs as u8, - VariableData::UInt16(rhs) => *lhs |= rhs as u8, - VariableData::UInt32(rhs) => *lhs |= rhs as u8, - VariableData::UInt64(rhs) => *lhs |= rhs as u8, - VariableData::Int8(rhs) => *lhs |= rhs as u8, - VariableData::Int16(rhs) => *lhs |= rhs as u8, - VariableData::Int32(rhs) => *lhs |= rhs as u8, - VariableData::Int64(rhs) => *lhs |= rhs as u8, - _ => panic!("Invalid type for bitwise or assign"), - }, - VariableData::UInt16(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs |= rhs as u16, - VariableData::UInt16(rhs) => *lhs |= rhs as u16, - VariableData::UInt32(rhs) => *lhs |= rhs as u16, - VariableData::UInt64(rhs) => *lhs |= rhs as u16, - VariableData::Int8(rhs) => *lhs |= rhs as u16, - VariableData::Int16(rhs) => *lhs |= rhs as u16, - VariableData::Int32(rhs) => *lhs |= rhs as u16, - VariableData::Int64(rhs) => *lhs |= rhs as u16, - _ => panic!("Invalid type for bitwise or assign"), - }, - VariableData::UInt32(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs |= rhs as u32, - VariableData::UInt16(rhs) => *lhs |= rhs as u32, - VariableData::UInt32(rhs) => *lhs |= rhs as u32, - VariableData::UInt64(rhs) => *lhs |= rhs as u32, - VariableData::Int8(rhs) => *lhs |= rhs as u32, - VariableData::Int16(rhs) => *lhs |= rhs as u32, - VariableData::Int32(rhs) => *lhs |= rhs as u32, - VariableData::Int64(rhs) => *lhs |= rhs as u32, - _ => panic!("Invalid type for bitwise or assign"), - }, - VariableData::UInt64(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs |= rhs as u64, - VariableData::UInt16(rhs) => *lhs |= rhs as u64, - VariableData::UInt32(rhs) => *lhs |= rhs as u64, - VariableData::UInt64(rhs) => *lhs |= rhs as u64, - VariableData::Int8(rhs) => *lhs |= rhs as u64, - VariableData::Int16(rhs) => *lhs |= rhs as u64, - VariableData::Int32(rhs) => *lhs |= rhs as u64, - VariableData::Int64(rhs) => *lhs |= rhs as u64, - _ => panic!("Invalid type for bitwise or assign"), - }, - - VariableData::Int8(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs |= rhs as i8, - VariableData::UInt16(rhs) => *lhs |= rhs as i8, - VariableData::UInt32(rhs) => *lhs |= rhs as i8, - VariableData::UInt64(rhs) => *lhs |= rhs as i8, - VariableData::Int8(rhs) => *lhs |= rhs as i8, - VariableData::Int16(rhs) => *lhs |= rhs as i8, - VariableData::Int32(rhs) => *lhs |= rhs as i8, - VariableData::Int64(rhs) => *lhs |= rhs as i8, - _ => panic!("Invalid type for bitwise or assign"), - }, - VariableData::Int16(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs |= rhs as i16, - VariableData::UInt16(rhs) => *lhs |= rhs as i16, - VariableData::UInt32(rhs) => *lhs |= rhs as i16, - VariableData::UInt64(rhs) => *lhs |= rhs as i16, - VariableData::Int8(rhs) => *lhs |= rhs as i16, - VariableData::Int16(rhs) => *lhs |= rhs as i16, - VariableData::Int32(rhs) => *lhs |= rhs as i16, - VariableData::Int64(rhs) => *lhs |= rhs as i16, - _ => panic!("Invalid type for bitwise or assign"), - }, - VariableData::Int32(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs |= rhs as i32, - VariableData::UInt16(rhs) => *lhs |= rhs as i32, - VariableData::UInt32(rhs) => *lhs |= rhs as i32, - VariableData::UInt64(rhs) => *lhs |= rhs as i32, - VariableData::Int8(rhs) => *lhs |= rhs as i32, - VariableData::Int16(rhs) => *lhs |= rhs as i32, - VariableData::Int32(rhs) => *lhs |= rhs as i32, - VariableData::Int64(rhs) => *lhs |= rhs as i32, - _ => panic!("Invalid type for bitwise or assign"), - }, - VariableData::Int64(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs |= rhs as i64, - VariableData::UInt16(rhs) => *lhs |= rhs as i64, - VariableData::UInt32(rhs) => *lhs |= rhs as i64, - VariableData::UInt64(rhs) => *lhs |= rhs as i64, - VariableData::Int8(rhs) => *lhs |= rhs as i64, - VariableData::Int16(rhs) => *lhs |= rhs as i64, - VariableData::Int32(rhs) => *lhs |= rhs as i64, - VariableData::Int64(rhs) => *lhs |= rhs as i64, - _ => panic!("Invalid type for bitwise or assign"), - }, - - _ => panic!("Invalid type for bitwise or assign"), - } - } -} - -#[derive(Debug, Clone)] -pub struct BitwiseXorAssign { - pub lhs: Operand, - pub rhs: Operand, -} -impl BitwiseXorAssign { - fn execute(&self, program: &mut VirtualMachine) { - let rhs = get_operand_value(program, &self.rhs).clone(); - let lhs = get_operand_value_mut(program, &self.lhs); - - match lhs { - VariableData::UInt8(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs ^= rhs as u8, - VariableData::UInt16(rhs) => *lhs ^= rhs as u8, - VariableData::UInt32(rhs) => *lhs ^= rhs as u8, - VariableData::UInt64(rhs) => *lhs ^= rhs as u8, - VariableData::Int8(rhs) => *lhs ^= rhs as u8, - VariableData::Int16(rhs) => *lhs ^= rhs as u8, - VariableData::Int32(rhs) => *lhs ^= rhs as u8, - VariableData::Int64(rhs) => *lhs ^= rhs as u8, - _ => panic!("Invalid type for bitwise xor assign"), - }, - VariableData::UInt16(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs ^= rhs as u16, - VariableData::UInt16(rhs) => *lhs ^= rhs as u16, - VariableData::UInt32(rhs) => *lhs ^= rhs as u16, - VariableData::UInt64(rhs) => *lhs ^= rhs as u16, - VariableData::Int8(rhs) => *lhs ^= rhs as u16, - VariableData::Int16(rhs) => *lhs ^= rhs as u16, - VariableData::Int32(rhs) => *lhs ^= rhs as u16, - VariableData::Int64(rhs) => *lhs ^= rhs as u16, - _ => panic!("Invalid type for bitwise xor assign"), - }, - VariableData::UInt32(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs ^= rhs as u32, - VariableData::UInt16(rhs) => *lhs ^= rhs as u32, - VariableData::UInt32(rhs) => *lhs ^= rhs as u32, - VariableData::UInt64(rhs) => *lhs ^= rhs as u32, - VariableData::Int8(rhs) => *lhs ^= rhs as u32, - VariableData::Int16(rhs) => *lhs ^= rhs as u32, - VariableData::Int32(rhs) => *lhs ^= rhs as u32, - VariableData::Int64(rhs) => *lhs ^= rhs as u32, - _ => panic!("Invalid type for bitwise xor assign"), - }, - VariableData::UInt64(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs ^= rhs as u64, - VariableData::UInt16(rhs) => *lhs ^= rhs as u64, - VariableData::UInt32(rhs) => *lhs ^= rhs as u64, - VariableData::UInt64(rhs) => *lhs ^= rhs as u64, - VariableData::Int8(rhs) => *lhs ^= rhs as u64, - VariableData::Int16(rhs) => *lhs ^= rhs as u64, - VariableData::Int32(rhs) => *lhs ^= rhs as u64, - VariableData::Int64(rhs) => *lhs ^= rhs as u64, - _ => panic!("Invalid type for bitwise xor assign"), - }, - - VariableData::Int8(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs ^= rhs as i8, - VariableData::UInt16(rhs) => *lhs ^= rhs as i8, - VariableData::UInt32(rhs) => *lhs ^= rhs as i8, - VariableData::UInt64(rhs) => *lhs ^= rhs as i8, - VariableData::Int8(rhs) => *lhs ^= rhs as i8, - VariableData::Int16(rhs) => *lhs ^= rhs as i8, - VariableData::Int32(rhs) => *lhs ^= rhs as i8, - VariableData::Int64(rhs) => *lhs ^= rhs as i8, - _ => panic!("Invalid type for bitwise xor assign"), - }, - VariableData::Int16(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs ^= rhs as i16, - VariableData::UInt16(rhs) => *lhs ^= rhs as i16, - VariableData::UInt32(rhs) => *lhs ^= rhs as i16, - VariableData::UInt64(rhs) => *lhs ^= rhs as i16, - VariableData::Int8(rhs) => *lhs ^= rhs as i16, - VariableData::Int16(rhs) => *lhs ^= rhs as i16, - VariableData::Int32(rhs) => *lhs ^= rhs as i16, - VariableData::Int64(rhs) => *lhs ^= rhs as i16, - _ => panic!("Invalid type for bitwise xor assign"), - }, - VariableData::Int32(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs ^= rhs as i32, - VariableData::UInt16(rhs) => *lhs ^= rhs as i32, - VariableData::UInt32(rhs) => *lhs ^= rhs as i32, - VariableData::UInt64(rhs) => *lhs ^= rhs as i32, - VariableData::Int8(rhs) => *lhs ^= rhs as i32, - VariableData::Int16(rhs) => *lhs ^= rhs as i32, - VariableData::Int32(rhs) => *lhs ^= rhs as i32, - VariableData::Int64(rhs) => *lhs ^= rhs as i32, - _ => panic!("Invalid type for bitwise xor assign"), - }, - VariableData::Int64(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs ^= rhs as i64, - VariableData::UInt16(rhs) => *lhs ^= rhs as i64, - VariableData::UInt32(rhs) => *lhs ^= rhs as i64, - VariableData::UInt64(rhs) => *lhs ^= rhs as i64, - VariableData::Int8(rhs) => *lhs ^= rhs as i64, - VariableData::Int16(rhs) => *lhs ^= rhs as i64, - VariableData::Int32(rhs) => *lhs ^= rhs as i64, - VariableData::Int64(rhs) => *lhs ^= rhs as i64, - _ => panic!("Invalid type for bitwise xor assign"), - }, - - _ => panic!("Invalid type for bitwise xor assign"), - } - } -} - -#[derive(Debug, Clone)] -pub struct ShiftLeftAssign { - pub lhs: Operand, - pub rhs: Operand, -} -impl ShiftLeftAssign { - fn execute(&self, program: &mut VirtualMachine) { - let rhs = get_operand_value(program, &self.rhs).clone(); - let lhs = get_operand_value_mut(program, &self.lhs); - - match lhs { - VariableData::UInt8(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - _ => panic!("Invalid type for left shift assign"), - }, - VariableData::UInt16(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - _ => panic!("Invalid type for left shift assign"), - }, - VariableData::UInt32(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - _ => panic!("Invalid type for left shift assign"), - }, - VariableData::UInt64(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - _ => panic!("Invalid type for left shift assign"), - }, - - VariableData::Int8(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - _ => panic!("Invalid type for left shift assign"), - }, - VariableData::Int16(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - _ => panic!("Invalid type for left shift assign"), - }, - VariableData::Int32(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - _ => panic!("Invalid type for left shift assign"), - }, - VariableData::Int64(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_shl(rhs as u32).0, - _ => panic!("Invalid type for left shift assign"), - }, - _ => panic!("Invalid type for left shift assign"), - } - } -} - -#[derive(Debug, Clone)] -pub struct ShiftRightAssign { - pub lhs: Operand, - pub rhs: Operand, -} -impl ShiftRightAssign { - fn execute(&self, program: &mut VirtualMachine) { - let rhs = get_operand_value(program, &self.rhs).clone(); - let lhs = get_operand_value_mut(program, &self.lhs); - - match lhs { - VariableData::UInt8(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - _ => panic!("Invalid type for right shift assign"), - }, - VariableData::UInt16(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - _ => panic!("Invalid type for right shift assign"), - }, - VariableData::UInt32(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - _ => panic!("Invalid type for right shift assign"), - }, - VariableData::UInt64(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - _ => panic!("Invalid type for right shift assign"), - }, - - VariableData::Int8(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - _ => panic!("Invalid type for right shift assign"), - }, - VariableData::Int16(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - _ => panic!("Invalid type for right shift assign"), - }, - VariableData::Int32(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - _ => panic!("Invalid type for right shift assign"), - }, - VariableData::Int64(ref mut lhs) => match rhs { - VariableData::UInt8(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::UInt16(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::UInt32(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::UInt64(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int8(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int16(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int32(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - VariableData::Int64(rhs) => *lhs = lhs.overflowing_shr(rhs as u32).0, - _ => panic!("Invalid type for right shift assign"), - }, - _ => panic!("Invalid type for right shift assign"), - } - } -} - -#[derive(Debug, Clone)] -pub struct Assign { - pub lhs_type: TypeInfo, - pub lhs: Operand, - pub rhs: Operand, -} -impl Assign { - fn execute(&self, program: &mut VirtualMachine) { - let rhs = get_operand_value(program, &self.rhs) - .cast_to(&self.lhs_type) - .expect(format!("Invalid cast to {:?}", &self.lhs_type).as_str()); - - *get_operand_value_mut(program, &self.lhs) = rhs; - } -} - -#[derive(Debug, Clone)] -pub struct AssignStruct { - pub count: usize, - pub lhs: Operand, - pub rhs: Operand, -} -impl AssignStruct { - fn execute(&self, program: &mut VirtualMachine) { - let lhs_address = get_operand_value(program, &self.lhs).to_u64() as usize; - let rhs_address = get_operand_value(program, &self.rhs).to_u64() as usize; - - for i in 0..self.count { - program.stack[lhs_address + i] = program.stack[rhs_address + i].clone(); - } - } + JumpZero(SizeType, Operand, LabelType), + JumpNotZero(SizeType, Operand, LabelType), + + Push(SizeType, Operand), + Pop(SizeType, Operand), + + /// bytes, src, dst + Memcpy(usize, Operand, Operand), + + /// float to float, ax, inplace + F2F(Float, Float), + /// float to int, ax, inplace + F2I(Float, Integer), + /// integer to float, ax, inplace + I2F(Integer, Float), + /// integer to integer, ax, inplace + I2I(Integer, Integer), + + AddI(SizeType, Operand, Operand, Operand), + AddF(SizeType, Operand, Operand, Operand), + SubI(SizeType, Operand, Operand, Operand), + SubF(SizeType, Operand, Operand, Operand), + + /// (src_size, src, dst) + /// dst must Be int32 (dword) + LogicalNot(SizeType, Operand, Operand), + Neg(SizeType, Operand), + BitNot(SizeType, Operand), + + BitAnd(SizeType, Operand, Operand), + BitOr(SizeType, Operand, Operand), + BitXor(SizeType, Operand, Operand), + + ShiftLeftI(SizeType, Operand, Operand), + ShiftLeftU(SizeType, Operand, Operand), + ShiftRightI(SizeType, Operand, Operand), + ShiftRightU(SizeType, Operand, Operand), + + Equal(SizeType, Operand, Operand, Operand), + LessThanI(SizeType, Operand, Operand, Operand), + LessThanU(SizeType, Operand, Operand, Operand), + LessThanF(SizeType, Operand, Operand, Operand), + + ModI(SizeType, Operand, Operand, Operand), + ModU(SizeType, Operand, Operand, Operand), + + MulF(SizeType, Operand, Operand, Operand), + MulI(SizeType, Operand, Operand, Operand), + MulU(SizeType, Operand, Operand, Operand), + + DivF(SizeType, Operand, Operand, Operand), + DivI(SizeType, Operand, Operand, Operand), + DivU(SizeType, Operand, Operand, Operand), } diff --git a/src/virtualmachine/mod.rs b/src/virtualmachine/mod.rs index 7bf47b0..ca4b27a 100644 --- a/src/virtualmachine/mod.rs +++ b/src/virtualmachine/mod.rs @@ -5,7 +5,8 @@ mod vm; pub type LabelType = usize; -pub use instruction::Instruction; - pub use generator::InstructionGenerator; +pub use instruction::Instruction; +pub use operand::Operand; +pub use operand::SizeType; pub use vm::VirtualMachine; diff --git a/src/virtualmachine/operand.rs b/src/virtualmachine/operand.rs index bcec1c3..34e58d5 100644 --- a/src/virtualmachine/operand.rs +++ b/src/virtualmachine/operand.rs @@ -1,43 +1,37 @@ -use crate::virtualmachine::variable::VariableData; -use crate::virtualmachine::vm::VirtualMachine; - -/// Type for Operand -/// Derefed: [rax + offset] -/// Register: rax -/// Value: constant value -#[derive(Debug, Clone)] -pub enum Operand { - Derefed(usize, isize), // number of register - Register(usize), // number of register - Value(VariableData), +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum SizeType { + Byte, + Word, + DWord, + QWord, } -/// helper function -pub(crate) fn get_operand_value<'a>( - // helper function - program: &'a VirtualMachine, - operand: &'a Operand, -) -> &'a VariableData { - match operand { - Operand::Derefed(register, offset) => { - &program.stack[(program.registers[*register].to_u64() as isize + *offset) as usize] +impl SizeType { + pub fn from_size(size: usize) -> SizeType { + match size { + 1 => SizeType::Byte, + 2 => SizeType::Word, + 4 => SizeType::DWord, + 8 => SizeType::QWord, + _ => panic!("Invalid size: {}", size), } - Operand::Register(register) => &program.registers[*register], - Operand::Value(val) => val, } -} -/// helper function -pub(crate) fn get_operand_value_mut<'a>( - // helper function - program: &'a mut VirtualMachine, - operand: &'a Operand, -) -> &'a mut VariableData { - match operand { - Operand::Derefed(register, offset) => { - &mut program.stack[(program.registers[*register].to_u64() as isize + *offset) as usize] - } - Operand::Register(register) => &mut program.registers[*register], - Operand::Value(_) => { - panic!("get_operand_value_mut: cannot get mutable reference from value") + pub fn to_size(&self) -> usize { + match self { + SizeType::Byte => 1, + SizeType::Word => 2, + SizeType::DWord => 4, + SizeType::QWord => 8, } } } + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum Operand { + /// value, size + Constant(u64), + /// register number + Register(usize), + /// [ register number ] + Deref(usize), +} +impl Operand {} diff --git a/src/virtualmachine/vm.rs b/src/virtualmachine/vm.rs index 1b9a5a8..ec0546b 100644 --- a/src/virtualmachine/vm.rs +++ b/src/virtualmachine/vm.rs @@ -1,40 +1,1015 @@ +use crate::ast2::Address; +use crate::ast2::Float; +use crate::ast2::Integer; + use super::Instruction; +use super::Operand; +use super::SizeType; + +#[derive(Debug, Clone, Copy)] +pub struct RegisterData { + pub bytes: u64, +} +impl Default for RegisterData { + fn default() -> Self { + RegisterData { bytes: 0 } + } +} +impl RegisterData {} /// Virtual Program /// have stack, registers, labels pub struct VirtualMachine { pub(crate) label_map: Vec, + pub(crate) text: Vec, + /// address of i'th function + pub(crate) functions: Vec, pub(crate) stack: Vec, - - /// each register is for single primitive type - /// rax, rbx, rcx, rdx, rtx, rbp, rsp - /// last tree registers are for - /// text section size, stack pointer and base pointer - pub(crate) registers: [u64; 7], + pub(crate) instructions: Vec, pub(crate) current_instruction: usize, - pub(crate) instructions: Vec, + + pub(crate) registers: [RegisterData; 7], } -pub const STACK_SIZE: usize = 10240; // stack size -pub const STACK_POINTER_REGISTER: usize = 6; // index of register for use as stack pointer (rsp) -pub const STACK_POINTER_BASE_REGISTER: usize = 5; // index of register for use as stack base pointer (rbp) -pub const TEXT_SIZE_REGISTER: usize = 4; // index of register for use as text section size (rtx) -pub const RAX: usize = 0; // index of register for use as rax -pub const RBX: usize = 1; // index of register for use as rax -pub const RCX: usize = 2; // index of register for use as rax -pub const RDX: usize = 3; // index of register for use as rax +pub(crate) const REGISTER_SP: usize = 6; // index of register for use as stack pointer (rsp) +pub(crate) const REGISTER_BP: usize = 5; // index of register for use as stack base pointer (rbp) + impl VirtualMachine { pub fn new() -> VirtualMachine { VirtualMachine { label_map: Vec::new(), stack: Vec::new(), + functions: Vec::new(), registers: Default::default(), current_instruction: 0, instructions: Vec::new(), + text: Vec::new(), + } + } + + fn get_bp(&self) -> u64 { + self.registers[REGISTER_BP].bytes + } + + unsafe fn get_as(buf: &[u8], address: usize) -> T { + *((&buf[address] as *const u8) as *const T) + } + unsafe fn set_as(buf: &mut [u8], address: usize, value: T) { + *((&mut buf[address] as *mut u8) as *mut T) = value; + } + + fn get_byte(&self, operand: Operand) -> u8 { + match operand { + Operand::Constant(value) => value as u8, + Operand::Register(register) => self.registers[register].bytes as u8, + Operand::Deref(register) => { + let address = self.registers[register].bytes; + match Address::from_u64(address) { + Address::Global(g) => self.stack[g], + Address::Local(l) => { + let address = self.get_bp() as usize + l; + self.stack[address] + } + Address::Function(_) => { + panic!("Function address in get_byte") + } + Address::Text(t) => self.text[t], + } + } + } + } + fn get_word(&self, operand: Operand) -> u16 { + match operand { + Operand::Constant(value) => value as u16, + Operand::Register(register) => self.registers[register].bytes as u16, + Operand::Deref(register) => { + let address = self.registers[register].bytes; + match Address::from_u64(address) { + Address::Global(g) => unsafe { Self::get_as::(&self.stack, g) }, + Address::Local(l) => { + let address = self.get_bp() as usize + l; + unsafe { Self::get_as::(&self.stack, address) } + } + Address::Function(_) => { + panic!("Function address in get_byte") + } + Address::Text(t) => unsafe { Self::get_as::(&self.text, t) }, + } + } + } + } + fn get_dword(&self, operand: Operand) -> u32 { + match operand { + Operand::Constant(value) => value as u32, + Operand::Register(register) => self.registers[register].bytes as u32, + Operand::Deref(register) => { + let address = self.registers[register].bytes; + match Address::from_u64(address) { + Address::Global(g) => unsafe { Self::get_as::(&self.stack, g) }, + Address::Local(l) => { + let address = self.get_bp() as usize + l; + unsafe { Self::get_as::(&self.stack, address) } + } + Address::Function(_) => { + panic!("Function address in get_dword") + } + Address::Text(t) => unsafe { Self::get_as::(&self.text, t) }, + } + } + } + } + fn get_qword(&self, operand: Operand) -> u64 { + match operand { + Operand::Constant(value) => value as u64, + Operand::Register(register) => self.registers[register].bytes as u64, + Operand::Deref(register) => { + let address = self.registers[register].bytes; + match Address::from_u64(address) { + Address::Global(g) => unsafe { Self::get_as::(&self.stack, g) }, + Address::Local(l) => { + let address = self.get_bp() as usize + l; + unsafe { Self::get_as::(&self.stack, address) } + } + Address::Function(f) => self.functions[f] as u64, + Address::Text(t) => unsafe { Self::get_as::(&self.text, t) }, + } + } + } + } + fn set_byte(&mut self, operand: Operand, value: u8) { + match operand { + Operand::Register(register) => self.registers[register].bytes = value as u64, + Operand::Deref(register) => { + let address = self.registers[register].bytes; + match Address::from_u64(address) { + Address::Global(g) => self.stack[g] = value, + Address::Local(l) => { + let address = self.get_bp() as usize + l; + self.stack[address] = value; + } + Address::Function(_) => { + panic!("Function address in set_byte") + } + Address::Text(t) => self.text[t] = value, + } + } + Operand::Constant(_) => { + unreachable!("Cannot set value to constant") + } + } + } + fn set_word(&mut self, operand: Operand, value: u16) { + match operand { + Operand::Register(register) => self.registers[register].bytes = value as u64, + Operand::Deref(register) => { + let address = self.registers[register].bytes; + match Address::from_u64(address) { + Address::Global(g) => unsafe { Self::set_as::(&mut self.stack, g, value) }, + Address::Local(l) => { + let address = self.get_bp() as usize + l; + unsafe { Self::set_as::(&mut self.stack, address, value) } + } + Address::Function(_) => { + unreachable!("Function address in get_byte") + } + Address::Text(_) => unreachable!("Text address in set_word"), + } + } + Operand::Constant(_) => { + unreachable!("Cannot set value to constant") + } + } + } + fn set_dword(&mut self, operand: Operand, value: u32) { + match operand { + Operand::Register(register) => self.registers[register].bytes = value as u64, + Operand::Deref(register) => { + let address = self.registers[register].bytes; + match Address::from_u64(address) { + Address::Global(g) => unsafe { Self::set_as::(&mut self.stack, g, value) }, + Address::Local(l) => { + let address = self.get_bp() as usize + l; + unsafe { Self::set_as::(&mut self.stack, address, value) } + } + Address::Function(_) => { + unreachable!("Function address in get_byte") + } + Address::Text(_) => unreachable!("Text address in set_dword"), + } + } + Operand::Constant(_) => { + unreachable!("Cannot set value to constant") + } + } + } + fn set_qword(&mut self, operand: Operand, value: u64) { + match operand { + Operand::Register(register) => self.registers[register].bytes = value as u64, + Operand::Deref(register) => { + let address = self.registers[register].bytes; + match Address::from_u64(address) { + Address::Global(g) => unsafe { Self::set_as::(&mut self.stack, g, value) }, + Address::Local(l) => { + let address = self.get_bp() as usize + l; + unsafe { Self::set_as::(&mut self.stack, address, value) } + } + Address::Function(_) => { + unreachable!("Function address in set_qword") + } + Address::Text(_) => unreachable!("Text address in set_qword"), + } + } + Operand::Constant(_) => { + unreachable!("Cannot set value to constant") + } + } + } + + pub fn cycle(&mut self) { + let instruction = self.instructions[self.current_instruction].clone(); + self.current_instruction += 1; + + match instruction { + Instruction::Move(size, from, to) => match size { + SizeType::Byte => { + let value = self.get_byte(from); + self.set_byte(to, value); + } + SizeType::Word => { + let value = self.get_word(from); + self.set_word(to, value); + } + SizeType::DWord => { + let value = self.get_dword(from); + self.set_dword(to, value); + } + SizeType::QWord => { + let value = self.get_qword(from); + self.set_qword(to, value); + } + }, + + Instruction::Jump(label) => { + self.current_instruction = self.label_map[label]; + } + + Instruction::JumpZero(size, operand, label) => match size { + SizeType::Byte => { + if self.get_byte(operand) == 0 { + self.current_instruction = self.label_map[label]; + } + } + SizeType::Word => { + if self.get_word(operand) == 0 { + self.current_instruction = self.label_map[label]; + } + } + SizeType::DWord => { + if self.get_dword(operand) == 0 { + self.current_instruction = self.label_map[label]; + } + } + SizeType::QWord => { + if self.get_qword(operand) == 0 { + self.current_instruction = self.label_map[label]; + } + } + }, + + Instruction::JumpNotZero(size, operand, label) => match size { + SizeType::Byte => { + if self.get_byte(operand) != 0 { + self.current_instruction = self.label_map[label]; + } + } + SizeType::Word => { + if self.get_word(operand) != 0 { + self.current_instruction = self.label_map[label]; + } + } + SizeType::DWord => { + if self.get_dword(operand) != 0 { + self.current_instruction = self.label_map[label]; + } + } + SizeType::QWord => { + if self.get_qword(operand) != 0 { + self.current_instruction = self.label_map[label]; + } + } + }, + Instruction::Push(size, src) => match size { + SizeType::Byte => { + let value = self.get_byte(src); + self.registers[REGISTER_SP].bytes -= 1; + let absolute_index = self.registers[REGISTER_SP].bytes; + self.stack[absolute_index as usize] = value; + } + SizeType::Word => { + let value = self.get_word(src); + self.registers[REGISTER_SP].bytes -= 2; + let absolute_index = self.registers[REGISTER_SP].bytes; + unsafe { Self::set_as::(&mut self.stack, absolute_index as usize, value) } + } + SizeType::DWord => { + let value = self.get_dword(src); + self.registers[REGISTER_SP].bytes -= 4; + let absolute_index = self.registers[REGISTER_SP].bytes; + unsafe { Self::set_as::(&mut self.stack, absolute_index as usize, value) } + } + SizeType::QWord => { + let value = self.get_qword(src); + self.registers[REGISTER_SP].bytes -= 8; + let absolute_index = self.registers[REGISTER_SP].bytes; + unsafe { Self::set_as::(&mut self.stack, absolute_index as usize, value) } + } + }, + Instruction::Pop(size, dst) => match size { + SizeType::Byte => { + let absolute_index = self.registers[REGISTER_SP].bytes; + let value = self.stack[absolute_index as usize]; + self.registers[REGISTER_SP].bytes += 1; + self.set_byte(dst, value); + } + SizeType::Word => { + let absolute_index = self.registers[REGISTER_SP].bytes; + let value = + unsafe { Self::get_as::(&self.stack, absolute_index as usize) }; + self.registers[REGISTER_SP].bytes += 2; + self.set_word(dst, value); + } + SizeType::DWord => { + let absolute_index = self.registers[REGISTER_SP].bytes; + let value = + unsafe { Self::get_as::(&self.stack, absolute_index as usize) }; + self.registers[REGISTER_SP].bytes += 4; + self.set_dword(dst, value); + } + SizeType::QWord => { + let absolute_index = self.registers[REGISTER_SP].bytes; + let value = + unsafe { Self::get_as::(&self.stack, absolute_index as usize) }; + self.registers[REGISTER_SP].bytes += 8; + self.set_qword(dst, value); + } + }, + + Instruction::Memcpy(bytes, src, dst) => { + let src_addr = match Address::from_u64(self.get_qword(src)) { + Address::Global(g) => g, + Address::Local(l) => self.get_bp() as usize + l, + _ => panic!("Invalid address for memcpy"), + }; + let dst_addr = match Address::from_u64(self.get_qword(dst)) { + Address::Global(g) => g, + Address::Local(l) => self.get_bp() as usize + l, + _ => panic!("Invalid address for memcpy"), + }; + + for i in 0..bytes { + self.stack[dst_addr + i] = self.stack[src_addr + i]; + } + } + + Instruction::F2F(from, to) => match (from, to) { + (Float::Float32, Float::Float64) => { + let bits = self.get_dword(Operand::Register(0)); + let value = f32::from_bits(bits) as f64; + self.set_qword(Operand::Register(0), value.to_bits()); + } + (Float::Float64, Float::Float32) => { + let bits = self.get_qword(Operand::Register(0)); + let value = f64::from_bits(bits) as f32; + self.set_dword(Operand::Register(0), value.to_bits()); + } + _ => {} + }, + Instruction::F2I(from, to) => { + let ivalue = match from { + Float::Float32 => { + let bits = self.get_dword(Operand::Register(0)); + f32::from_bits(bits) as i64 + } + Float::Float64 => { + let bits = self.get_qword(Operand::Register(0)); + f64::from_bits(bits) as i64 + } + }; + match to { + Integer::UInt8 | Integer::Int8 => { + self.set_byte(Operand::Register(0), ivalue as u8); + } + Integer::UInt16 | Integer::Int16 => { + self.set_word(Operand::Register(0), ivalue as u16); + } + Integer::UInt32 | Integer::Int32 => { + self.set_dword(Operand::Register(0), ivalue as u32); + } + Integer::UInt64 | Integer::Int64 => { + self.set_qword(Operand::Register(0), ivalue as u64); + } + } + } + Instruction::I2F(from, to) => match from { + Integer::UInt8 => { + let value = self.get_byte(Operand::Register(0)); + match to { + Float::Float32 => { + let fvalue = value as f32; + self.set_dword(Operand::Register(0), fvalue.to_bits()); + } + Float::Float64 => { + let fvalue = value as f64; + self.set_qword(Operand::Register(0), fvalue.to_bits()); + } + } + } + Integer::Int8 => { + let value = self.get_byte(Operand::Register(0)) as i8; + match to { + Float::Float32 => { + let fvalue = value as f32; + self.set_dword(Operand::Register(0), fvalue.to_bits()); + } + Float::Float64 => { + let fvalue = value as f64; + self.set_qword(Operand::Register(0), fvalue.to_bits()); + } + } + } + Integer::UInt16 => { + let value = self.get_word(Operand::Register(0)); + match to { + Float::Float32 => { + let fvalue = value as f32; + self.set_dword(Operand::Register(0), fvalue.to_bits()); + } + Float::Float64 => { + let fvalue = value as f64; + self.set_qword(Operand::Register(0), fvalue.to_bits()); + } + } + } + Integer::Int16 => { + let value = self.get_word(Operand::Register(0)) as i16; + match to { + Float::Float32 => { + let fvalue = value as f32; + self.set_dword(Operand::Register(0), fvalue.to_bits()); + } + Float::Float64 => { + let fvalue = value as f64; + self.set_qword(Operand::Register(0), fvalue.to_bits()); + } + } + } + Integer::UInt32 => { + let value = self.get_dword(Operand::Register(0)); + match to { + Float::Float32 => { + let fvalue = value as f32; + self.set_dword(Operand::Register(0), fvalue.to_bits()); + } + Float::Float64 => { + let fvalue = value as f64; + self.set_qword(Operand::Register(0), fvalue.to_bits()); + } + } + } + Integer::Int32 => { + let value = self.get_dword(Operand::Register(0)) as i32; + match to { + Float::Float32 => { + let fvalue = value as f32; + self.set_dword(Operand::Register(0), fvalue.to_bits()); + } + Float::Float64 => { + let fvalue = value as f64; + self.set_qword(Operand::Register(0), fvalue.to_bits()); + } + } + } + Integer::UInt64 => { + let value = self.get_qword(Operand::Register(0)); + match to { + Float::Float32 => { + let fvalue = value as f32; + self.set_dword(Operand::Register(0), fvalue.to_bits()); + } + Float::Float64 => { + let fvalue = value as f64; + self.set_qword(Operand::Register(0), fvalue.to_bits()); + } + } + } + Integer::Int64 => { + let value = self.get_qword(Operand::Register(0)) as i64; + match to { + Float::Float32 => { + let fvalue = value as f32; + self.set_dword(Operand::Register(0), fvalue.to_bits()); + } + Float::Float64 => { + let fvalue = value as f64; + self.set_qword(Operand::Register(0), fvalue.to_bits()); + } + } + } + }, + + Instruction::I2I(from, to) => { + let value = match from { + Integer::UInt8 => self.get_byte(Operand::Register(0)) as u64, + Integer::Int8 => self.get_byte(Operand::Register(0)) as i8 as i64 as u64, + Integer::UInt16 => self.get_word(Operand::Register(0)) as u64, + Integer::Int16 => self.get_word(Operand::Register(0)) as i16 as i64 as u64, + Integer::UInt32 => self.get_dword(Operand::Register(0)) as u64, + Integer::Int32 => self.get_dword(Operand::Register(0)) as i32 as i64 as u64, + Integer::UInt64 => self.get_qword(Operand::Register(0)), + Integer::Int64 => self.get_qword(Operand::Register(0)) as i64 as u64, + }; + + match to { + Integer::UInt8 => self.set_byte(Operand::Register(0), value as u8), + Integer::Int8 => self.set_byte(Operand::Register(0), value as i8 as u8), + Integer::UInt16 => self.set_word(Operand::Register(0), value as u16), + Integer::Int16 => self.set_word(Operand::Register(0), value as i16 as u16), + Integer::UInt32 => self.set_dword(Operand::Register(0), value as u32), + Integer::Int32 => self.set_dword(Operand::Register(0), value as i32 as u32), + Integer::UInt64 => self.set_qword(Operand::Register(0), value), + Integer::Int64 => self.set_qword(Operand::Register(0), value as i64 as u64), + } + } + + Instruction::AddI(size, lhs, rhs, out) => match size { + SizeType::Byte => { + let value = self.get_byte(lhs).wrapping_add(self.get_byte(rhs)); + self.set_byte(out, value); + } + SizeType::Word => { + let value = self.get_word(lhs).wrapping_add(self.get_word(rhs)); + self.set_word(out, value); + } + SizeType::DWord => { + let value = self.get_dword(lhs).wrapping_add(self.get_dword(rhs)); + self.set_dword(out, value); + } + SizeType::QWord => { + let value = self.get_qword(lhs).wrapping_add(self.get_qword(rhs)); + self.set_qword(out, value); + } + }, + Instruction::AddF(size, lhs, rhs, out) => match size { + SizeType::DWord => { + let value = + f32::from_bits(self.get_dword(lhs)) + f32::from_bits(self.get_dword(rhs)); + self.set_dword(out, value.to_bits()); + } + SizeType::QWord => { + let value = + f64::from_bits(self.get_qword(lhs)) + f64::from_bits(self.get_qword(rhs)); + self.set_qword(out, value.to_bits()); + } + _ => unreachable!("Invalid size for AddF"), + }, + + Instruction::SubI(size, lhs, rhs, out) => match size { + SizeType::Byte => { + let value = self.get_byte(lhs).wrapping_sub(self.get_byte(rhs)); + self.set_byte(out, value); + } + SizeType::Word => { + let value = self.get_word(lhs).wrapping_sub(self.get_word(rhs)); + self.set_word(out, value); + } + SizeType::DWord => { + let value = self.get_dword(lhs).wrapping_sub(self.get_dword(rhs)); + self.set_dword(out, value); + } + SizeType::QWord => { + let value = self.get_qword(lhs).wrapping_sub(self.get_qword(rhs)); + self.set_qword(out, value); + } + }, + Instruction::SubF(size, lhs, rhs, out) => match size { + SizeType::DWord => { + let value = + f32::from_bits(self.get_dword(lhs)) - f32::from_bits(self.get_dword(rhs)); + self.set_dword(out, value.to_bits()); + } + SizeType::QWord => { + let value = + f64::from_bits(self.get_qword(lhs)) - f64::from_bits(self.get_qword(rhs)); + self.set_qword(out, value.to_bits()); + } + _ => unreachable!("Invalid size for AddF"), + }, + + Instruction::LogicalNot(size, src, dst) => { + let iszero = match size { + SizeType::Byte => self.get_byte(src) == 0, + SizeType::Word => self.get_word(src) == 0, + SizeType::DWord => self.get_dword(src) == 0, + SizeType::QWord => self.get_qword(src) == 0, + }; + let value = if iszero { 1 } else { 0 }; + self.set_dword(dst, value); + } + Instruction::BitNot(size, src) => match size { + SizeType::Byte => { + let value = !self.get_byte(src); + self.set_byte(src, value); + } + SizeType::Word => { + let value = !self.get_word(src); + self.set_word(src, value); + } + SizeType::DWord => { + let value = !self.get_dword(src); + self.set_dword(src, value); + } + SizeType::QWord => { + let value = !self.get_qword(src); + self.set_qword(src, value); + } + }, + Instruction::Neg(size, src) => match size { + SizeType::Byte => { + let value = self.get_byte(src).wrapping_neg(); + self.set_byte(src, value); + } + SizeType::Word => { + let value = self.get_word(src).wrapping_neg(); + self.set_word(src, value); + } + SizeType::DWord => { + let value = self.get_dword(src).wrapping_neg(); + self.set_dword(src, value); + } + SizeType::QWord => { + let value = self.get_qword(src).wrapping_neg(); + self.set_qword(src, value); + } + }, + + Instruction::BitAnd(size, lhs, rhs) => match size { + SizeType::Byte => { + let value = self.get_byte(lhs) & self.get_byte(rhs); + self.set_byte(lhs, value); + } + SizeType::Word => { + let value = self.get_word(lhs) & self.get_word(rhs); + self.set_word(lhs, value); + } + SizeType::DWord => { + let value = self.get_dword(lhs) & self.get_dword(rhs); + self.set_dword(lhs, value); + } + SizeType::QWord => { + let value = self.get_qword(lhs) & self.get_qword(rhs); + self.set_qword(lhs, value); + } + }, + + Instruction::BitOr(size, lhs, rhs) => match size { + SizeType::Byte => { + let value = self.get_byte(lhs) | self.get_byte(rhs); + self.set_byte(lhs, value); + } + SizeType::Word => { + let value = self.get_word(lhs) | self.get_word(rhs); + self.set_word(lhs, value); + } + SizeType::DWord => { + let value = self.get_dword(lhs) | self.get_dword(rhs); + self.set_dword(lhs, value); + } + SizeType::QWord => { + let value = self.get_qword(lhs) | self.get_qword(rhs); + self.set_qword(lhs, value); + } + }, + Instruction::BitXor(size, lhs, rhs) => match size { + SizeType::Byte => { + let value = self.get_byte(lhs) ^ self.get_byte(rhs); + self.set_byte(lhs, value); + } + SizeType::Word => { + let value = self.get_word(lhs) ^ self.get_word(rhs); + self.set_word(lhs, value); + } + SizeType::DWord => { + let value = self.get_dword(lhs) ^ self.get_dword(rhs); + self.set_dword(lhs, value); + } + SizeType::QWord => { + let value = self.get_qword(lhs) ^ self.get_qword(rhs); + self.set_qword(lhs, value); + } + }, + + Instruction::ShiftLeftI(size, src, bits) => match size { + SizeType::Byte => { + let rhs = self.get_byte(bits) as u32; + let value = (self.get_byte(src) as i8).wrapping_shl(rhs); + self.set_byte(src, value as u8); + } + SizeType::Word => { + let rhs = self.get_byte(bits) as u32; + let value = (self.get_word(src) as i16).wrapping_shl(rhs); + self.set_word(src, value as u16); + } + SizeType::DWord => { + let rhs = self.get_byte(bits) as u32; + let value = (self.get_dword(src) as i32).wrapping_shl(rhs); + self.set_dword(src, value as u32); + } + SizeType::QWord => { + let rhs = self.get_byte(bits) as u32; + let value = (self.get_qword(src) as i64).wrapping_shl(rhs); + self.set_qword(src, value as u64); + } + }, + Instruction::ShiftLeftU(size, src, bits) => match size { + SizeType::Byte => { + let rhs = self.get_byte(bits) as u32; + let value = self.get_byte(src).wrapping_shl(rhs); + self.set_byte(src, value); + } + SizeType::Word => { + let rhs = self.get_byte(bits) as u32; + let value = self.get_word(src).wrapping_shl(rhs); + self.set_word(src, value); + } + SizeType::DWord => { + let rhs = self.get_byte(bits) as u32; + let value = self.get_dword(src).wrapping_shl(rhs); + self.set_dword(src, value); + } + SizeType::QWord => { + let rhs = self.get_byte(bits) as u32; + let value = self.get_qword(src).wrapping_shl(rhs); + self.set_qword(src, value); + } + }, + + Instruction::ShiftRightI(size, src, bits) => match size { + SizeType::Byte => { + let rhs = self.get_byte(bits) as u32; + let value = (self.get_byte(src) as i8).wrapping_shr(rhs); + self.set_byte(src, value as u8); + } + SizeType::Word => { + let rhs = self.get_byte(bits) as u32; + let value = (self.get_word(src) as i16).wrapping_shr(rhs); + self.set_word(src, value as u16); + } + SizeType::DWord => { + let rhs = self.get_byte(bits) as u32; + let value = (self.get_dword(src) as i32).wrapping_shr(rhs); + self.set_dword(src, value as u32); + } + SizeType::QWord => { + let rhs = self.get_byte(bits) as u32; + let value = (self.get_qword(src) as i64).wrapping_shr(rhs); + self.set_qword(src, value as u64); + } + }, + + Instruction::ShiftRightU(size, src, bits) => match size { + SizeType::Byte => { + let rhs = self.get_byte(bits) as u32; + let value = self.get_byte(src).wrapping_shr(rhs); + self.set_byte(src, value); + } + SizeType::Word => { + let rhs = self.get_byte(bits) as u32; + let value = self.get_word(src).wrapping_shr(rhs); + self.set_word(src, value); + } + SizeType::DWord => { + let rhs = self.get_byte(bits) as u32; + let value = self.get_dword(src).wrapping_shr(rhs); + self.set_dword(src, value); + } + SizeType::QWord => { + let rhs = self.get_byte(bits) as u32; + let value = self.get_qword(src).wrapping_shr(rhs); + self.set_qword(src, value); + } + }, + Instruction::Equal(size, lhs, rhs, out) => { + let value = match size { + SizeType::Byte => self.get_byte(lhs) == self.get_byte(rhs), + SizeType::Word => self.get_word(lhs) == self.get_word(rhs), + SizeType::DWord => self.get_dword(lhs) == self.get_dword(rhs), + SizeType::QWord => self.get_qword(lhs) == self.get_qword(rhs), + }; + self.set_dword(out, if value { 1 } else { 0 }); + } + + Instruction::LessThanI(size, lhs, rhs, out) => { + let value = match size { + SizeType::Byte => (self.get_byte(lhs) as i8) < (self.get_byte(rhs) as i8), + SizeType::Word => (self.get_word(lhs) as i16) < (self.get_word(rhs) as i16), + SizeType::DWord => (self.get_dword(lhs) as i32) < (self.get_dword(rhs) as i32), + SizeType::QWord => (self.get_qword(lhs) as i64) < (self.get_qword(rhs) as i64), + }; + self.set_dword(out, if value { 1 } else { 0 }); + } + Instruction::LessThanU(size, lhs, rhs, out) => { + let value = match size { + SizeType::Byte => self.get_byte(lhs) < self.get_byte(rhs), + SizeType::Word => self.get_word(lhs) < self.get_word(rhs), + SizeType::DWord => self.get_dword(lhs) < self.get_dword(rhs), + SizeType::QWord => self.get_qword(lhs) < self.get_qword(rhs), + }; + self.set_dword(out, if value { 1 } else { 0 }); + } + Instruction::LessThanF(size, lhs, rhs, out) => { + let value = match size { + SizeType::DWord => { + f32::from_bits(self.get_dword(lhs)) < f32::from_bits(self.get_dword(rhs)) + } + SizeType::QWord => { + f64::from_bits(self.get_qword(lhs)) < f64::from_bits(self.get_qword(rhs)) + } + _ => panic!("Invalid size for LessThanF : {:?}", size), + }; + self.set_dword(out, if value { 1 } else { 0 }); + } + + Instruction::ModI(size, lhs, rhs, out) => match size { + SizeType::Byte => { + let lhs = self.get_byte(lhs) as i8; + let rhs = self.get_byte(rhs) as i8; + self.set_byte(out, (lhs % rhs) as u8); + } + SizeType::Word => { + let lhs = self.get_word(lhs) as i16; + let rhs = self.get_word(rhs) as i16; + self.set_word(out, (lhs % rhs) as u16); + } + SizeType::DWord => { + let lhs = self.get_dword(lhs) as i32; + let rhs = self.get_dword(rhs) as i32; + self.set_dword(out, (lhs % rhs) as u32); + } + SizeType::QWord => { + let lhs = self.get_qword(lhs) as i64; + let rhs = self.get_qword(rhs) as i64; + self.set_qword(out, (lhs % rhs) as u64); + } + }, + + Instruction::ModU(size, lhs, rhs, out) => match size { + SizeType::Byte => { + let lhs = self.get_byte(lhs); + let rhs = self.get_byte(rhs); + self.set_byte(out, lhs % rhs); + } + SizeType::Word => { + let lhs = self.get_word(lhs); + let rhs = self.get_word(rhs); + self.set_word(out, lhs % rhs); + } + SizeType::DWord => { + let lhs = self.get_dword(lhs); + let rhs = self.get_dword(rhs); + self.set_dword(out, lhs % rhs); + } + SizeType::QWord => { + let lhs = self.get_qword(lhs); + let rhs = self.get_qword(rhs); + self.set_qword(out, lhs % rhs); + } + }, + + Instruction::DivU(size, lhs, rhs, out) => match size { + SizeType::Byte => { + let lhs = self.get_byte(lhs); + let rhs = self.get_byte(rhs); + self.set_byte(out, lhs / rhs); + } + SizeType::Word => { + let lhs = self.get_word(lhs); + let rhs = self.get_word(rhs); + self.set_word(out, lhs / rhs); + } + SizeType::DWord => { + let lhs = self.get_dword(lhs); + let rhs = self.get_dword(rhs); + self.set_dword(out, lhs / rhs); + } + SizeType::QWord => { + let lhs = self.get_qword(lhs); + let rhs = self.get_qword(rhs); + self.set_qword(out, lhs / rhs); + } + }, + + Instruction::DivI(size, lhs, rhs, out) => match size { + SizeType::Byte => { + let lhs = self.get_byte(lhs) as i8; + let rhs = self.get_byte(rhs) as i8; + self.set_byte(out, (lhs / rhs) as u8); + } + SizeType::Word => { + let lhs = self.get_word(lhs) as i16; + let rhs = self.get_word(rhs) as i16; + self.set_word(out, (lhs / rhs) as u16); + } + SizeType::DWord => { + let lhs = self.get_dword(lhs) as i32; + let rhs = self.get_dword(rhs) as i32; + self.set_dword(out, (lhs / rhs) as u32); + } + SizeType::QWord => { + let lhs = self.get_qword(lhs) as i64; + let rhs = self.get_qword(rhs) as i64; + self.set_qword(out, (lhs / rhs) as u64); + } + }, + + Instruction::DivF(size, lhs, rhs, out) => match size { + SizeType::DWord => { + let lhs = f32::from_bits(self.get_dword(lhs)); + let rhs = f32::from_bits(self.get_dword(rhs)); + self.set_dword(out, (lhs / rhs).to_bits()); + } + SizeType::QWord => { + let lhs = f64::from_bits(self.get_qword(lhs)); + let rhs = f64::from_bits(self.get_qword(rhs)); + self.set_qword(out, (lhs / rhs).to_bits()); + } + _ => panic!("Invalid size for DivF : {:?}", size), + }, + + Instruction::MulI(size, lhs, rhs, out) => match size { + SizeType::Byte => { + let lhs = self.get_byte(lhs) as i8; + let rhs = self.get_byte(rhs) as i8; + self.set_byte(out, (lhs * rhs) as u8); + } + SizeType::Word => { + let lhs = self.get_word(lhs) as i16; + let rhs = self.get_word(rhs) as i16; + self.set_word(out, (lhs * rhs) as u16); + } + SizeType::DWord => { + let lhs = self.get_dword(lhs) as i32; + let rhs = self.get_dword(rhs) as i32; + self.set_dword(out, (lhs * rhs) as u32); + } + SizeType::QWord => { + let lhs = self.get_qword(lhs) as i64; + let rhs = self.get_qword(rhs) as i64; + self.set_qword(out, (lhs * rhs) as u64); + } + }, + + Instruction::MulU(size, lhs, rhs, out) => match size { + SizeType::Byte => { + let lhs = self.get_byte(lhs); + let rhs = self.get_byte(rhs); + self.set_byte(out, lhs * rhs); + } + SizeType::Word => { + let lhs = self.get_word(lhs); + let rhs = self.get_word(rhs); + self.set_word(out, lhs * rhs); + } + SizeType::DWord => { + let lhs = self.get_dword(lhs); + let rhs = self.get_dword(rhs); + self.set_dword(out, lhs * rhs); + } + SizeType::QWord => { + let lhs = self.get_qword(lhs); + let rhs = self.get_qword(rhs); + self.set_qword(out, lhs * rhs); + } + }, + + Instruction::MulF(size, lhs, rhs, out) => match size { + SizeType::DWord => { + let lhs = f32::from_bits(self.get_dword(lhs)); + let rhs = f32::from_bits(self.get_dword(rhs)); + self.set_dword(out, (lhs * rhs).to_bits()); + } + SizeType::QWord => { + let lhs = f64::from_bits(self.get_qword(lhs)); + let rhs = f64::from_bits(self.get_qword(rhs)); + self.set_qword(out, (lhs * rhs).to_bits()); + } + _ => panic!("Invalid size for MulF : {:?}", size), + }, + + _ => unimplemented!("Instruction not implemented: {:?}", instruction), } } }