mclangc/src/parser/ast/statement.rs
2026-01-17 16:31:40 +02:00

260 lines
8.4 KiB
Rust

use anyhow::bail;
use crate::{common::loc::LocBox, lerror, parser::ast::expr::Path};
use super::{expr::{Block, Expr}, literal::Literal, typ::Type, Char, Ident, Number, Program, TString};
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum Statement {
Fn(Function),
TypeAlias(TypeAlias),
Struct(Struct),
Enum(Enum),
ConstVar(ConstVar),
StaticVar(StaticVar),
Let(Let),
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Let {
pub name: Ident,
pub typ: Option<LocBox<Type>>,
pub val: Option<LocBox<Expr>>,
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct ConstVar {
pub name: Ident,
pub typ: LocBox<Type>,
pub val: LocBox<Expr>,
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct StaticVar {
pub name: Ident,
pub typ: LocBox<Type>,
pub val: LocBox<Expr>,
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct TypeAlias {
pub name: Ident,
pub typ: LocBox<Type>,
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Struct {
pub name: Ident,
pub fields: Vec<(Ident, LocBox<Type>)>,
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Enum {
pub name: Ident,
pub fields: Vec<Ident>,
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Function {
pub struct_name: Option<Ident>,
pub name: Ident,
pub params: Vec<(Ident, LocBox<Type>)>,
pub ret_type: Option<LocBox<Type>>,
pub qual_const: bool,
pub qual_extern: Option<TString>, // abi
pub body: Option<Block>, // If None then its a type declaration
}
impl Function {
pub fn get_full_name(&self) -> String {
if let Some(sn) = &self.struct_name {
format!("{sn}__S__{}", self.name.0)
} else {
format!("{}", self.name.0)
}
}
pub fn get_full_name_pretty(&self) -> String {
if let Some(sn) = &self.struct_name {
format!("{sn}::{}", self.name.0)
} else {
format!("{}", self.name.0)
}
}
pub fn get_def_as_str(&self) -> String {
let mut f = String::new();
f.push_str(&format!("fn {} (", self.get_full_name_pretty()));
let mut first = true;
for (name, typ) in &self.params {
if first {
first = false;
} else {
f.push_str(", ");
}
f.push_str(&format!("{name}: {}", typ.inner()));
}
f.push_str(")");
if let Some(ret) = &self.ret_type {
f.push_str(&format!(" -> {}", ret.inner()));
}
f.push_str(";");
f
}
}
impl Struct {
pub fn get_size(&self, program: &Program) -> anyhow::Result<usize> {
let mut size = 0;
for (_, v) in &self.fields {
size += v.inner().size_of(program)?;
}
Ok(size)
}
pub fn get_offset_of(&self, program: &Program, field: &Ident) -> anyhow::Result<usize> {
let mut size = 0;
for (k, v) in &self.fields {
if k == field {
return Ok(size);
}
size += v.inner().size_of(program)?;
}
bail!("Field not found")
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum ConstDataTyp {
Byte(u8),
AddrOfConst(Ident),
AddrOfStatic(Ident),
AddrOfFunc(Ident),
}
pub fn get_constant_data_as_bytes(program: &Program, value: LocBox<Expr>, is_little_endian: bool, must_be_number: bool) -> anyhow::Result<Vec<ConstDataTyp>> {
match value.inner() {
Expr::Literal(lit) => {
match lit {
Literal::Char(Char(c)) => {
if must_be_number {
lerror!(value.loc(), "Expected number got char");
bail!("")
}
Ok(vec![ConstDataTyp::Byte(*c as u8)])
},
Literal::String(TString { val, cstr }) => {
if must_be_number {
lerror!(value.loc(), "Expected number got string");
bail!("")
}
let mut val = val.chars().into_iter().map(|f| ConstDataTyp::Byte(f as u8)).collect::<Vec<_>>();
if *cstr {
val.push(ConstDataTyp::Byte(0));
}
Ok(val)
}
Literal::Number(Number { val, base: _, signed: _ }) => {
let mut buf = Vec::new();
let mut inc = 0;
while inc < 8 {
buf.push(ConstDataTyp::Byte(((val << 8*inc) & 0xff) as u8));
inc += 1;
}
if is_little_endian {
buf.reverse();
}
Ok(buf)
}
Literal::Array(arr) => {
if must_be_number {
lerror!(value.loc(), "Expected number got array");
bail!("")
}
let mut bytes = Vec::new();
if arr.len() < 1 {
return Ok(vec![]);
}
for item in arr {
let mut data = get_constant_data_as_bytes(program, item.clone(), is_little_endian, must_be_number)?;
bytes.append(&mut data);
}
Ok(bytes)
}
Literal::ArrayRepeat { val, count } => {
if must_be_number {
lerror!(value.loc(), "Expected number got repeating array");
bail!("")
}
let mut val = get_constant_data_as_bytes(program, (**val).clone(), is_little_endian, must_be_number)?;
let mut num = Vec::new();
let mut inc = 0;
while inc < 8 {
num.push(ConstDataTyp::Byte(((count << 8*inc) & 0xff) as u8));
inc += 1;
}
if is_little_endian {
num.reverse();
}
let mut count = 0 as usize;
for b in num {
let ConstDataTyp::Byte(b) = b else {unreachable!()};
count = b as usize;
count <<= 8;
}
let orig = val.clone();
for _ in 0..count {
val.append(&mut orig.clone());
}
Ok(val)
}
Literal::Ident(name) => {
if let Some(var) = program.const_vars.get(name) {
Ok(get_constant_data_as_bytes(program, var.val.clone(), is_little_endian, must_be_number)?)
} else if let Some(_) = program.static_vars.get(name) {
lerror!(value.loc(), "Statics cannot be passed by value, use a reference");
bail!("")
} else if let Some(_) = program.functions.get(name) {
Ok(vec![ConstDataTyp::AddrOfFunc(name.clone())])
} else {
lerror!(value.loc(), "Unable to find ident '{name}'");
bail!("")
}
}
//Literal::Struct { name, fields } => {
// if must_be_number {
// lerror!(value.loc(), "Expected number got struct literal");
// bail!("")
// }
// let Some(strct) = program.structs.get(name) else {
// lerror!(value.loc(), "Could not find struct {name}");
// bail!("")
// };
//
// let mut strct_fields = HashMap::new();
// for (name, typ) in &strct.inner().fields {
// strct_fields.insert(name, typ);
// }
//
// for (name, val) in fields {
// if let Some(_fld) = strct_fields.get(name) {
// // TODO: Actually check if the fields are the right type
//
// }
// }
// todo!()
//}
}
}
_ => unreachable!()
}
}