use crate::lexer::*;
use core::convert::TryFrom;
use std::collections::HashMap;
use std::collections::HashSet;
pub mod types;
use types::Type;
pub type SymbolTable = HashMap<String, Option<Type>>;
#[derive(Debug, Clone)]
pub struct Module {
pub path: String,
pub imports: HashSet<String>,
pub func: Vec<Function>,
pub structs: Vec<StructDef>,
pub globals: Vec<String>,
}
impl Module {
pub fn merge_with(&mut self, mut other: Module) {
self.func.append(&mut other.func);
self.structs.append(&mut other.structs);
self.globals.append(&mut other.globals)
}
pub fn get_symbol_table(&self) -> SymbolTable {
let mut table = SymbolTable::new();
for func in self.func.clone() {
table.insert(func.name, func.ret_type);
}
table
}
}
#[derive(Debug, Clone)]
pub struct Function {
pub name: String,
pub arguments: Vec<Variable>,
pub body: Statement,
pub ret_type: Option<Type>,
}
#[derive(Debug, Clone)]
pub struct StructDef {
pub name: String,
pub fields: Vec<Variable>,
pub methods: Vec<Function>,
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct Variable {
pub name: String,
pub ty: Option<Type>,
}
impl AsRef<Variable> for Variable {
fn as_ref(&self) -> &Self {
self
}
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum Statement {
Block {
statements: Vec<Statement>,
scope: Vec<Variable>,
},
Declare {
variable: Variable,
value: Option<Expression>,
},
Assign {
lhs: Box<Expression>,
rhs: Box<Expression>,
},
Return(Option<Expression>),
If {
condition: Expression,
body: Box<Statement>,
else_branch: Option<Box<Statement>>,
},
While {
condition: Expression,
body: Box<Statement>,
},
For {
ident: Variable,
expr: Expression,
body: Box<Statement>,
},
Match {
subject: Expression,
arms: Vec<MatchArm>,
},
Break,
Continue,
Exp(Expression),
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum Expression {
Int(usize),
Str(String),
Bool(bool),
Selff,
Array {
capacity: usize,
elements: Vec<Expression>,
},
FunctionCall {
fn_name: String,
args: Vec<Expression>,
},
Variable(String),
ArrayAccess {
name: String,
index: Box<Expression>,
},
BinOp {
lhs: Box<Expression>,
op: BinOp,
rhs: Box<Expression>,
},
StructInitialization {
name: String,
fields: HashMap<String, Box<Expression>>,
},
FieldAccess {
expr: Box<Expression>,
field: Box<Expression>,
},
}
impl TryFrom<Token> for Expression {
type Error = String;
fn try_from(token: Token) -> std::result::Result<Self, String> {
let kind = token.kind;
match kind {
TokenKind::Identifier(val) => Ok(Expression::Variable(val)),
TokenKind::Literal(Value::Int) => Ok(Expression::Int(
token
.raw
.parse()
.map_err(|_| "Int value could not be parsed")?,
)),
TokenKind::Keyword(Keyword::Boolean) => match token.raw.as_ref() {
"true" => Ok(Expression::Bool(true)),
"false" => Ok(Expression::Bool(false)),
_ => Err("Boolean value could not be parsed".into()),
},
TokenKind::Literal(Value::Str(string)) => Ok(Expression::Str(string)),
_ => Err("Value could not be parsed".into()),
}
}
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum MatchArm {
Case(Expression, Statement),
Else(Statement),
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum BinOp {
Addition,
Subtraction,
Multiplication,
Division,
Modulus,
LessThan,
LessThanOrEqual,
GreaterThan,
GreaterThanOrEqual,
Equal,
NotEqual,
And,
Or,
AddAssign,
SubtractAssign,
MultiplyAssign,
DivideAssign,
}
impl TryFrom<TokenKind> for BinOp {
type Error = String;
fn try_from(token: TokenKind) -> Result<BinOp, String> {
match token {
TokenKind::Star => Ok(BinOp::Multiplication),
TokenKind::Slash => Ok(BinOp::Division),
TokenKind::Plus => Ok(BinOp::Addition),
TokenKind::Minus => Ok(BinOp::Subtraction),
TokenKind::Percent => Ok(BinOp::Modulus),
TokenKind::LessThan => Ok(BinOp::LessThan),
TokenKind::GreaterThan => Ok(BinOp::GreaterThan),
TokenKind::Equals => Ok(BinOp::Equal),
TokenKind::LessThanOrEqual => Ok(BinOp::LessThanOrEqual),
TokenKind::GreaterThanOrEqual => Ok(BinOp::GreaterThanOrEqual),
TokenKind::NotEqual => Ok(BinOp::NotEqual),
TokenKind::And => Ok(BinOp::And),
TokenKind::Or => Ok(BinOp::Or),
TokenKind::PlusEqual => Ok(BinOp::AddAssign),
TokenKind::MinusEqual => Ok(BinOp::SubtractAssign),
TokenKind::StarEqual => Ok(BinOp::MultiplyAssign),
TokenKind::SlashEqual => Ok(BinOp::DivideAssign),
other => Err(format!(
"Token {:?} cannot be converted into a BinOp",
other
)),
}
}
}