6699333b2c
- If statements work properly now (hopefully) - still issues with while loops pushing vars to the stack. need scoping implemented to fix this! - refactored registers.rs and fixed faulty logic. - made register allocation optimisations
286 lines
6.7 KiB
Rust
286 lines
6.7 KiB
Rust
use core::fmt;
|
|
|
|
#[allow(unused)]
|
|
#[derive(Debug, Clone)]
|
|
pub enum CompilerError {
|
|
UnexpectedToken(String),
|
|
UnexpectedEndOfInput,
|
|
UnexpectedCharacter(char),
|
|
Undefined(Name),
|
|
InvalidSyntax(String),
|
|
Generic(String),
|
|
UnknownType,
|
|
TypeMismatch(TypeId, TypeId),
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
|
pub struct Name {
|
|
pub name: String,
|
|
pub namespace: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct Program {
|
|
pub declarations: Vec<Declaration>,
|
|
}
|
|
|
|
#[allow(unused)]
|
|
#[derive(Debug, Clone)]
|
|
pub enum Declaration {
|
|
Function {
|
|
name: String,
|
|
return_type: TypeId,
|
|
params: Vec<Variable>,
|
|
body: Block,
|
|
},
|
|
Variable {
|
|
var: Variable,
|
|
init: Option<ConstExpr>,
|
|
is_const: bool,
|
|
},
|
|
Dependency(Dependency),
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct Dependency {
|
|
pub name: String,
|
|
pub path: String,
|
|
}
|
|
|
|
#[allow(unused)]
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum TypeId {
|
|
U8,
|
|
U16,
|
|
U32,
|
|
I8,
|
|
I16,
|
|
I32,
|
|
Bool,
|
|
Char,
|
|
Void,
|
|
Ptr(Box<TypeId>),
|
|
Ref(Box<TypeId>),
|
|
Array(Box<TypeId>, usize),
|
|
Struct { name: Name, fields: Vec<TypeId> },
|
|
}
|
|
|
|
impl fmt::Display for TypeId {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
Self::U8 => write!(f, "u8"),
|
|
Self::U16 => write!(f, "u16"),
|
|
Self::U32 => write!(f, "u32"),
|
|
Self::I8 => write!(f, "i8"),
|
|
Self::I16 => write!(f, "i16"),
|
|
Self::I32 => write!(f, "i32"),
|
|
Self::Bool => write!(f, "bool"),
|
|
Self::Char => write!(f, "char"),
|
|
Self::Void => write!(f, "void"),
|
|
Self::Ptr(t) => write!(f, "*{}", t),
|
|
Self::Ref(t) => write!(f, "&{}", t),
|
|
Self::Array(t, len) => write!(f, "[{}; {}]", t, len),
|
|
Self::Struct { name, fields } => {
|
|
write!(f, "struct {} {{", name)?;
|
|
for (i, field) in fields.iter().enumerate() {
|
|
write!(f, "{}: {}", i, field)?;
|
|
}
|
|
write!(f, "}}")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub type Block = Vec<Statement>;
|
|
|
|
#[allow(unused)]
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct Variable {
|
|
pub name: String,
|
|
pub type_id: TypeId,
|
|
}
|
|
|
|
#[allow(unused)]
|
|
#[derive(Debug, Clone)]
|
|
pub enum Statement {
|
|
Block(Block),
|
|
Declaration {
|
|
var: Variable,
|
|
value: Option<Expression>,
|
|
},
|
|
Assign {
|
|
varname: String,
|
|
value: Expression,
|
|
},
|
|
PtrWrite {
|
|
ptr: Expression,
|
|
value: Expression,
|
|
},
|
|
Expression {
|
|
expr: Expression,
|
|
},
|
|
If {
|
|
condition: Expression,
|
|
then_stmt: Block,
|
|
else_stmt: Block,
|
|
},
|
|
While {
|
|
condition: Expression,
|
|
body: Vec<Statement>,
|
|
},
|
|
Loop(Block),
|
|
Defer(Call),
|
|
Break,
|
|
Continue,
|
|
Return(Option<Expression>),
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum ConstExpr {
|
|
Number(i32),
|
|
String(String),
|
|
}
|
|
|
|
impl fmt::Display for ConstExpr {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
match self {
|
|
ConstExpr::Number(n) => write!(f, "{}", n),
|
|
ConstExpr::String(s) => write!(f, "\"{}\"", s),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[allow(unused)]
|
|
#[derive(Debug, Clone)]
|
|
pub enum Expression {
|
|
Empty,
|
|
Binary {
|
|
op: BinaryOperator,
|
|
left: Box<Expression>,
|
|
right: Box<Expression>,
|
|
|
|
// Post-Semantic Analysis
|
|
type_id: Option<TypeId>,
|
|
},
|
|
Unary {
|
|
op: UnaryOperator,
|
|
operand: Box<Expression>,
|
|
|
|
// Post-Semantic Analysis
|
|
type_id: Option<TypeId>,
|
|
},
|
|
Variable {
|
|
name: Name,
|
|
expr_type: Option<TypeId>,
|
|
},
|
|
Call {
|
|
func: Call,
|
|
|
|
// Post-Semantic Analysis
|
|
type_id: Option<TypeId>,
|
|
},
|
|
Number {
|
|
value: isize,
|
|
|
|
// Post-Semantic Analysis
|
|
type_id: Option<TypeId>,
|
|
},
|
|
StringLiteral(String),
|
|
CharLiteral(char),
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct Call {
|
|
pub name: Name,
|
|
pub args: Vec<Expression>,
|
|
}
|
|
|
|
impl Expression {
|
|
pub fn is_pure(&self) -> bool {
|
|
match self {
|
|
Expression::Number { .. } => true,
|
|
Expression::StringLiteral(_) => true,
|
|
Expression::CharLiteral(_) => true,
|
|
Expression::Call { .. } => false,
|
|
Expression::Binary { left, right, .. } => left.is_pure() && right.is_pure(),
|
|
Expression::Unary { operand, .. } => operand.is_pure(),
|
|
Expression::Empty => true,
|
|
Expression::Variable { .. } => true,
|
|
}
|
|
}
|
|
|
|
pub fn type_id(&self) -> Result<TypeId, CompilerError> {
|
|
match self {
|
|
Expression::Number { type_id, .. } => {
|
|
type_id.clone().ok_or(CompilerError::UnknownType)
|
|
}
|
|
Expression::StringLiteral(_) => Ok(TypeId::Ptr(Box::new(TypeId::Char))),
|
|
Expression::CharLiteral(_) => Ok(TypeId::Char),
|
|
Expression::Call { type_id, .. } => {
|
|
type_id.clone().ok_or(CompilerError::UnknownType)
|
|
}
|
|
Expression::Binary { type_id, .. } => {
|
|
type_id.clone().ok_or(CompilerError::UnknownType)
|
|
}
|
|
Expression::Unary { type_id, .. } => {
|
|
type_id.clone().ok_or(CompilerError::UnknownType)
|
|
}
|
|
Expression::Empty => Ok(TypeId::Void),
|
|
Expression::Variable { expr_type, .. } => {
|
|
expr_type.clone().ok_or(CompilerError::UnknownType)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[allow(unused)]
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum BinaryOperator {
|
|
Add,
|
|
Sub,
|
|
Mul,
|
|
Div,
|
|
Eq,
|
|
Ne,
|
|
Lt,
|
|
Gt,
|
|
Le,
|
|
Ge,
|
|
}
|
|
|
|
impl fmt::Display for BinaryOperator {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
match self {
|
|
BinaryOperator::Add => write!(f, "+"),
|
|
BinaryOperator::Sub => write!(f, "-"),
|
|
BinaryOperator::Mul => write!(f, "*"),
|
|
BinaryOperator::Div => write!(f, "/"),
|
|
BinaryOperator::Eq => write!(f, "=="),
|
|
BinaryOperator::Ne => write!(f, "!="),
|
|
BinaryOperator::Lt => write!(f, "<"),
|
|
BinaryOperator::Gt => write!(f, ">"),
|
|
BinaryOperator::Le => write!(f, "<="),
|
|
BinaryOperator::Ge => write!(f, ">="),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum UnaryOperator {
|
|
Plus,
|
|
Minus,
|
|
Reference,
|
|
Dereference,
|
|
}
|
|
|
|
impl fmt::Display for UnaryOperator {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
match self {
|
|
UnaryOperator::Plus => write!(f, "+"),
|
|
UnaryOperator::Minus => write!(f, "-"),
|
|
UnaryOperator::Dereference => write!(f, "*"),
|
|
UnaryOperator::Reference => write!(f, "&"),
|
|
}
|
|
}
|
|
}
|