201b18069b
proving to be a challenge
496 lines
13 KiB
Rust
496 lines
13 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),
|
|
Unimplemented(String),
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
|
pub struct Name {
|
|
pub name: String,
|
|
pub namespace: Option<String>,
|
|
}
|
|
impl Name {
|
|
pub fn new(name: impl Into<String>, namespace: Option<String>) -> Self {
|
|
Self {
|
|
name: name.into(),
|
|
namespace,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[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),
|
|
Struct {
|
|
name: Name,
|
|
fields: Vec<Variable>,
|
|
},
|
|
}
|
|
|
|
#[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>),
|
|
Tuple(Vec<TypeId>),
|
|
Array {
|
|
r#type: Box<TypeId>,
|
|
size: usize,
|
|
},
|
|
UnknownCustom {
|
|
name: Name,
|
|
generics: Vec<TypeId>,
|
|
},
|
|
Struct {
|
|
name: Name,
|
|
fields: Vec<TypeId>,
|
|
generics: Vec<TypeId>,
|
|
},
|
|
}
|
|
|
|
impl TypeId {
|
|
pub fn size(&self) -> usize {
|
|
match self {
|
|
Self::U8 => 1,
|
|
Self::U16 => 2,
|
|
Self::U32 => 4,
|
|
Self::I8 => 1,
|
|
Self::I16 => 2,
|
|
Self::I32 => 4,
|
|
Self::Bool => 1,
|
|
Self::Char => 1,
|
|
Self::Void => 0,
|
|
Self::Ptr(t) => t.size(),
|
|
Self::Ref(t) => t.size(),
|
|
Self::Tuple(types) => types.iter().map(|t| t.size()).sum(),
|
|
Self::Array { r#type, size } => r#type.size() * size,
|
|
Self::UnknownCustom { .. } => 1, /* TODO: calculate type size during */
|
|
// semantic analysis
|
|
Self::Struct { fields, .. } => fields.iter().map(|t| t.size()).sum(),
|
|
}
|
|
}
|
|
}
|
|
|
|
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::Tuple(elems) => write!(
|
|
f,
|
|
"({})",
|
|
elems
|
|
.iter()
|
|
.map(|t| t.to_string())
|
|
.collect::<Vec<String>>()
|
|
.join(", ")
|
|
),
|
|
Self::Array { r#type, size } => write!(f, "[{}; {}]", r#type, size),
|
|
Self::UnknownCustom { name, generics } => {
|
|
write!(
|
|
f,
|
|
"{}<{}>",
|
|
name,
|
|
generics
|
|
.iter()
|
|
.map(|t| t.to_string())
|
|
.collect::<Vec<String>>()
|
|
.join(", ")
|
|
)
|
|
}
|
|
Self::Struct {
|
|
name,
|
|
fields,
|
|
generics,
|
|
} => write!(
|
|
f,
|
|
"struct<{}> {} {{{}}}",
|
|
generics
|
|
.iter()
|
|
.map(|t| t.to_string())
|
|
.collect::<Vec<String>>()
|
|
.join(", "),
|
|
name,
|
|
fields
|
|
.iter()
|
|
.map(|t| t.to_string())
|
|
.collect::<Vec<String>>()
|
|
.join(", ")
|
|
),
|
|
}
|
|
}
|
|
}
|
|
|
|
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,
|
|
operator: AssignmentOperator,
|
|
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>,
|
|
},
|
|
UnaryPostfix {
|
|
op: UnaryOperator,
|
|
operand: Box<Expression>,
|
|
|
|
// Post-Semantic Analysis
|
|
type_id: Option<TypeId>,
|
|
},
|
|
Variable {
|
|
name: Name,
|
|
expr_type: Option<TypeId>,
|
|
},
|
|
TypeCast {
|
|
expr: Box<Expression>,
|
|
target_type: TypeId,
|
|
|
|
// Post-Semantic Analysis
|
|
type_id: Option<TypeId>,
|
|
},
|
|
IndexAccess {
|
|
expr: Box<Expression>,
|
|
index: Box<Expression>,
|
|
|
|
// Post-Semantic Analysis
|
|
type_id: Option<TypeId>,
|
|
},
|
|
MemberAccess {
|
|
expr: Box<Expression>,
|
|
field_name: Name,
|
|
|
|
// Post-Semantic Analysis
|
|
type_id: Option<TypeId>,
|
|
},
|
|
Call {
|
|
func: Call,
|
|
|
|
// Post-Semantic Analysis
|
|
type_id: Option<TypeId>,
|
|
},
|
|
Number(Number),
|
|
StringLiteral(String),
|
|
CharLiteral(char),
|
|
ArrayLiteral {
|
|
elements: Vec<Expression>,
|
|
type_id: Option<TypeId>,
|
|
},
|
|
StructLiteral {
|
|
name: Name,
|
|
fields: Vec<(Name, Expression)>,
|
|
type_id: Option<TypeId>,
|
|
},
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum Number {
|
|
Signed(i32, Option<TypeId>),
|
|
Unsigned(u32, Option<TypeId>),
|
|
}
|
|
|
|
#[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::UnaryPostfix { operand, .. } => operand.is_pure(),
|
|
Expression::Empty => true,
|
|
Expression::Variable { .. } => true,
|
|
Expression::TypeCast { expr, .. } => expr.is_pure(),
|
|
Expression::IndexAccess { expr, index, .. } => {
|
|
expr.is_pure() && index.is_pure()
|
|
}
|
|
Expression::MemberAccess { expr, .. } => expr.is_pure(),
|
|
Expression::ArrayLiteral { elements, .. } => {
|
|
elements.iter().all(|element| element.is_pure())
|
|
}
|
|
Expression::StructLiteral { fields, .. } => {
|
|
fields.iter().all(|(_, expr)| expr.is_pure())
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn type_id(&self) -> Result<TypeId, CompilerError> {
|
|
match self {
|
|
Expression::Number(
|
|
Number::Signed(_, type_id) | Number::Unsigned(_, 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::UnaryPostfix { 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)
|
|
}
|
|
Expression::TypeCast { type_id, .. } => {
|
|
type_id.clone().ok_or(CompilerError::UnknownType)
|
|
}
|
|
Expression::IndexAccess { expr, .. } => expr.type_id(),
|
|
Expression::MemberAccess { expr, .. } => expr.type_id(),
|
|
Expression::ArrayLiteral { elements, .. } => {
|
|
let element_type = elements
|
|
.first()
|
|
.map_or(TypeId::Void, |e| e.type_id().unwrap_or(TypeId::Void));
|
|
Ok(TypeId::Array {
|
|
r#type: Box::new(element_type),
|
|
size: elements.len(),
|
|
})
|
|
}
|
|
Expression::StructLiteral { name, fields, .. } => {
|
|
let fields = fields
|
|
.iter()
|
|
.map(|(_, expr)| expr.type_id())
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
Ok(TypeId::Struct {
|
|
name: name.clone(),
|
|
fields,
|
|
generics: Vec::new(),
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum AssignmentOperator {
|
|
Assign,
|
|
AddAssign,
|
|
SubAssign,
|
|
MulAssign,
|
|
DivAssign,
|
|
ModAssign,
|
|
AndAssign,
|
|
OrAssign,
|
|
XorAssign,
|
|
LeftShiftAssign,
|
|
RightShiftAssign,
|
|
}
|
|
|
|
#[allow(unused)]
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum BinaryOperator {
|
|
// arithmetic
|
|
Add,
|
|
Sub,
|
|
Mul,
|
|
Div,
|
|
Mod,
|
|
|
|
// comparison
|
|
Equal,
|
|
NotEqual,
|
|
LessThan,
|
|
GreaterThan,
|
|
LessOrEqual,
|
|
GreaterOrEqual,
|
|
|
|
// bitwise
|
|
BitwiseAnd,
|
|
BitwiseOr,
|
|
BitwiseXor,
|
|
|
|
// logical
|
|
LogicalAnd,
|
|
LogicalOr,
|
|
|
|
// shift
|
|
LeftShift,
|
|
RightShift,
|
|
}
|
|
|
|
impl fmt::Display for BinaryOperator {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
match self {
|
|
Self::Add => write!(f, "+"),
|
|
Self::Sub => write!(f, "-"),
|
|
Self::Mul => write!(f, "*"),
|
|
Self::Div => write!(f, "/"),
|
|
Self::Mod => write!(f, "%"),
|
|
Self::Equal => write!(f, "=="),
|
|
Self::NotEqual => write!(f, "!="),
|
|
Self::LessThan => write!(f, "<"),
|
|
Self::GreaterThan => write!(f, ">"),
|
|
Self::LessOrEqual => write!(f, "<="),
|
|
Self::GreaterOrEqual => write!(f, ">="),
|
|
Self::BitwiseAnd => write!(f, "&"),
|
|
Self::BitwiseOr => write!(f, "|"),
|
|
Self::BitwiseXor => write!(f, "^"),
|
|
Self::LogicalAnd => write!(f, "&&"),
|
|
Self::LogicalOr => write!(f, "||"),
|
|
Self::LeftShift => write!(f, "<<"),
|
|
Self::RightShift => write!(f, ">>"),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum UnaryOperator {
|
|
Plus,
|
|
Minus,
|
|
AddressOf,
|
|
Dereference,
|
|
BitwiseNot,
|
|
LogicalNot,
|
|
Increment,
|
|
Decrement,
|
|
SizeOf,
|
|
}
|
|
|
|
impl fmt::Display for UnaryOperator {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
match self {
|
|
Self::Increment => write!(f, "++"),
|
|
Self::Decrement => write!(f, "--"),
|
|
Self::Plus => write!(f, "+"),
|
|
Self::Minus => write!(f, "-"),
|
|
Self::Dereference => write!(f, "*"),
|
|
Self::AddressOf => write!(f, "&"),
|
|
Self::BitwiseNot => write!(f, "~"),
|
|
Self::LogicalNot => write!(f, "!"),
|
|
Self::SizeOf => write!(f, "sizeof"),
|
|
}
|
|
}
|
|
}
|