Compare commits

...

2 Commits

Author SHA1 Message Date
1f4645ed24 Upgrade to rust 2024
Wow this project is old
2026-01-17 16:39:01 +02:00
158b76fe39 :3 2026-01-17 16:31:40 +02:00
20 changed files with 793 additions and 119 deletions

View File

@ -1,7 +1,7 @@
[package]
name = "mclangc"
version = "0.1.0"
edition = "2021"
edition = "2024"
default-run = "mclangc"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -27,7 +27,7 @@ impl Loc {
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct LocBox<T: Clone + Debug> {
inner: T,
loc: Loc

View File

@ -110,7 +110,7 @@ pub mod log {
#[macro_export]
macro_rules! lerror {
($loc:expr, $($arg:tt)*) => {
($loc:expr_2021, $($arg:tt)*) => {
if cfg!(debug_assertions) {
crate::logger::_log_with_loc(Some((file!(), line!(), column!())), format!("{}", $loc), crate::logger::Level::Error, &format!($($arg)*))
} else {
@ -120,7 +120,7 @@ pub mod log {
}
#[macro_export]
macro_rules! lwarn {
($loc:expr, $($arg:tt)*) => {
($loc:expr_2021, $($arg:tt)*) => {
if cfg!(debug_assertions) {
crate::logger::_log_with_loc(Some((file!(), line!(), column!())), format!("{}", $loc), crate::logger::Level::Warn, &format!($($arg)*))
} else {
@ -130,7 +130,7 @@ pub mod log {
}
#[macro_export]
macro_rules! linfo {
($loc:expr, $($arg:tt)*) => {
($loc:expr_2021, $($arg:tt)*) => {
if cfg!(debug_assertions) {
crate::logger::_log_with_loc(Some((file!(), line!(), column!())), format!("{}", $loc), crate::logger::Level::Info, &format!($($arg)*))
} else {
@ -140,7 +140,7 @@ pub mod log {
}
#[macro_export]
macro_rules! lhelp {
($loc:expr, $($arg:tt)*) => {
($loc:expr_2021, $($arg:tt)*) => {
if cfg!(debug_assertions) {
crate::logger::_log_with_loc(Some((file!(), line!(), column!())), format!("{}", $loc), crate::logger::Level::Help, &format!($($arg)*))
} else {
@ -150,7 +150,7 @@ pub mod log {
}
#[macro_export]
macro_rules! ldebug {
($loc:expr, $($arg:tt)*) => {
($loc:expr_2021, $($arg:tt)*) => {
if cfg!(debug_assertions) {
crate::logger::_log_with_loc(Some((file!(), line!(), column!())), format!("{}", $loc), crate::logger::Level::Debug, &format!($($arg)*))
} else {

View File

@ -25,8 +25,9 @@ fn main() -> anyhow::Result<()> {
info!("Parsing {file}");
let mut prog = mclangc::parser::parse_program(tokens)?;
info!("Validating {file}");
dbg!(&prog);
mclangc::validator::validate_code(&mut prog)?;
// dbg!(&prog);
//dbg!(&prog);
progs.push((fp, prog));
}

View File

@ -1,10 +1,10 @@
use std::{collections::HashMap, fmt::Display};
use std::{collections::BTreeMap, fmt::Display};
use crate::{common::loc::LocBox, tokeniser::tokentype::*};
use crate::{common::loc::LocBox, parser::ast::{Program, literal::Literal}, tokeniser::tokentype::*};
use super::{typ::Type, Ast};
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum Expr {
// Comment(Comment),
Group(Box<LocBox<Expr>>),
@ -58,7 +58,7 @@ pub enum Expr {
If(IfExpr),
Struct {
path: Path,
fields: HashMap<Ident, LocBox<Expr>>,
fields: BTreeMap<Ident, LocBox<Expr>>,
},
Return(Box<Option<LocBox<Expr>>>),
Break,
@ -74,17 +74,30 @@ impl Expr {
let Expr::Path(p) = self else {panic!("Unwrapping")};
p.clone()
}
pub fn as_number(&self, prog: &Program) -> Option<Number> {
match self {
Self::Literal(Literal::Number(num)) => Some(*num),
Self::Path(Path(path)) => {
if let Some(val) = prog.get_const_var(path.last().unwrap()) {
val.1.inner().val.inner().as_number(prog)
} else {
None
}
}
_ => None
}
}
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct CallParams(pub Vec<LocBox<Expr>>);
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Block(pub Vec<Ast>);
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Hash)]
pub struct Path(pub Vec<Ident>);
impl Display for Path {
@ -100,14 +113,14 @@ impl Display for Path {
}
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct IfExpr {
pub test: Box<LocBox<Expr>>,
pub body: Block,
pub else_if: Option<IfBranchExpr>
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum IfBranchExpr {
ElseIf(Box<IfExpr>),
Else(Block)

View File

@ -1,10 +1,9 @@
use std::collections::HashMap;
use crate::{common::loc::LocBox, tokeniser::tokentype::*};
use crate::{common::{Loc, loc::LocBox}, parser::ast::{Program, typ::Type}, tokeniser::tokentype::*, validator::{predefined::SIZE, validate_expr}};
use super::{expr::Expr, typ::Type, Ast};
use super::expr::Expr;
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum Literal {
Number(Number),
Ident(Ident),
@ -13,6 +12,36 @@ pub enum Literal {
Array(Vec<LocBox<Expr>>),
ArrayRepeat {
val: Box<LocBox<Expr>>,
count: Box<LocBox<Expr>>,
count: usize,
},
}
impl Literal {
pub fn to_type(&self, prog: &mut Program) -> anyhow::Result<Type> {
let t = match self {
Self::Number(_) => Type::Builtin { name: String::from("usize"), size: SIZE as u8, signed: true },
Self::Ident(ident) => Type::Owned(ident.clone()),
Self::String(_) => Type::Owned(Ident(String::from("str"))),
Self::Char(_) => Type::Owned(Ident(String::from("char"))),
Self::Array(arr) => {
if arr.is_empty() {
Type::SizedArray {
inner: Box::new(Type::Builtin { name: "void".to_string(), size: 0, signed: false }),
count: LocBox::new(&Loc::default(), Expr::Literal(Literal::Number(Number { val: 0, base: 10, signed: false })))
}
} else {
let item = arr.first().unwrap();
Type::SizedArray {
inner: Box::new(validate_expr(prog, item.inner())?.unwrap()),
count: LocBox::new(item.loc(), Expr::Literal(Literal::Number(Number { val: arr.len(), base: 10, signed: false })))
}
}
}
Self::ArrayRepeat { val, count } => {
Type::SizedArray { inner: Box::new(validate_expr(prog, val.inner())?.unwrap()), count: LocBox::new(val.loc(), Expr::Literal(Literal::Number(Number { val: *count, base: 10, signed: false })))}
}
};
Ok(t)
}
}

View File

@ -2,7 +2,7 @@ use std::collections::HashMap;
use statement::{ConstVar, Enum, Function, StaticVar, Struct};
use crate::{common::loc::LocBox, validator::predefined::TypeType};
use crate::{common::loc::LocBox, parser::ast::{expr::Path, statement::Let, typ::Type}};
pub use crate::tokeniser::tokentype::*;
pub mod expr;
@ -10,19 +10,99 @@ pub mod literal;
pub mod statement;
pub mod typ;
#[derive(Debug, Clone)]
pub struct Scope {
pub vars: HashMap<Ident, LocBox<Let>>,
pub static_vars: HashMap<Ident, StaticVar>,
pub const_vars: HashMap<Ident, ConstVar>,
pub inner_scope: Option<Box<Scope>>
}
#[derive(Debug, Clone)]
pub struct Program {
pub ast: expr::Block,
pub structs: HashMap<Ident, LocBox<Struct>>,
pub enums: HashMap<Ident, LocBox<Enum>>,
pub types: HashMap<Ident, TypeType>,
pub types: HashMap<Ident, LocBox<Type>>,
pub functions: HashMap<Ident, LocBox<Function>>,
pub member_functions: HashMap<Ident, HashMap<Ident, LocBox<Function>>>,
pub static_vars: HashMap<Ident, StaticVar>,
pub const_vars: HashMap<Ident, ConstVar>
pub const_vars: HashMap<Ident, ConstVar>,
pub scope: Option<Scope>
}
#[derive(Debug, Clone)]
impl Scope {
pub fn get_var(&self, name: &Ident) -> Option<(Ident, LocBox<Let>)> {
if let Some(inner) = &self.inner_scope {
if let Some((ident, var)) = inner.get_var(name) {
return Some((ident, var));
}
}
if let Some(var) = self.vars.get(name) {
return Some((name.clone(), var.clone()));
}
None
}
pub fn get_static_var(&self, name: &Ident) -> Option<(Ident, LocBox<StaticVar>)> {
if let Some(inner) = &self.inner_scope {
if let Some((ident, var)) = inner.get_static_var(name) {
return Some((ident, var));
}
}
if let Some(var) = self.static_vars.get(name) {
return Some((name.clone(), LocBox::new(var.typ.loc(), var.clone())));
}
None
}
pub fn get_const_var(&self, name: &Ident) -> Option<(Ident, LocBox<ConstVar>)> {
if let Some(inner) = &self.inner_scope {
if let Some((ident, var)) = inner.get_const_var(name) {
return Some((ident, var));
}
}
if let Some(var) = self.const_vars.get(name) {
return Some((name.clone(), LocBox::new(var.typ.loc(), var.clone())));
}
None
}
}
impl Program {
pub fn get_var(&self, name: &Ident) -> Option<(Ident, LocBox<Let>)> {
if let Some(scope) = &self.scope {
scope.get_var(name)
} else {
None
}
}
pub fn get_static_var(&self, name: &Ident) -> Option<(Ident, LocBox<StaticVar>)> {
if let Some(scope) = &self.scope {
if let Some((name, var)) = scope.get_static_var(name) {
return Some((name, var));
}
}
if let Some(var) = self.static_vars.get(name) {
return Some((name.clone(), LocBox::new(var.typ.loc(), var.clone())));
}
None
}
pub fn get_const_var(&self, name: &Ident) -> Option<(Ident, LocBox<ConstVar>)> {
if let Some(scope) = &self.scope {
if let Some((name, var)) = scope.get_const_var(name) {
return Some((name, var));
}
}
if let Some(var) = self.const_vars.get(name) {
return Some((name.clone(), LocBox::new(var.typ.loc(), var.clone())));
}
None
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum Ast {
Expr(LocBox<expr::Expr>),
Statement(LocBox<statement::Statement>),

View File

@ -1,13 +1,12 @@
use std::collections::HashMap;
use anyhow::bail;
use crate::{common::{loc::LocBox, Loc}, lerror};
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)]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum Statement {
Fn(Function),
TypeAlias(TypeAlias),
@ -15,46 +14,49 @@ pub enum Statement {
Enum(Enum),
ConstVar(ConstVar),
StaticVar(StaticVar),
Let {
name: Ident,
typ: Option<LocBox<Type>>,
val: Option<LocBox<Expr>>,
},
Let(Let),
}
#[derive(Debug, Clone)]
#[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)]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct StaticVar {
pub name: Ident,
pub typ: LocBox<Type>,
pub val: LocBox<Expr>,
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct TypeAlias {
pub name: Ident,
pub typ: LocBox<Type>,
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Struct {
pub name: Ident,
pub fields: Vec<(Ident, LocBox<Type>)>,
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Enum {
pub name: Ident,
pub fields: Vec<Ident>,
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Function {
pub struct_name: Option<Ident>,
pub name: Ident,
@ -123,7 +125,7 @@ impl Struct {
}
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum ConstDataTyp {
Byte(u8),
AddrOfConst(Ident),
@ -189,7 +191,18 @@ pub fn get_constant_data_as_bytes(program: &Program, value: LocBox<Expr>, is_lit
bail!("")
}
let mut val = get_constant_data_as_bytes(program, (**val).clone(), is_little_endian, must_be_number)?;
let num = get_constant_data_as_bytes(program, (**count).clone(), is_little_endian, true)?;
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!()};

View File

@ -2,11 +2,11 @@ use std::fmt::Display;
use anyhow::bail;
use crate::{common::{loc::LocBox, Loc}, logger::log, validator::predefined::TypeType};
use crate::common::loc::LocBox;
use super::{expr::Expr, literal::Literal, Ident, Program};
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum Type {
Ref {
inner: Box<Type>,
@ -20,12 +20,84 @@ pub enum Type {
inner: Box<Type>,
},
Owned(Ident),
Builtin {
name: String,
size: u8,
signed: bool,
}
}
impl Type {
pub fn get_absolute_value(&self, program: &Program) -> anyhow::Result<Self> {
match self {
Self::Ref { inner, .. } => inner.get_absolute_value(program),
Self::Owned(ident) => {
if let Some(var) = program.get_var(ident) {
Ok(var.1.inner().typ.clone().expect("type should be computed if were already using it").inner().clone())
} else {
bail!("");
}
}
Self::SizedArray { .. } |
Self::Builtin { .. } |
Self::UnsizedArray { .. } => Ok(self.clone()),
}
}
pub fn is_numeric(&self, program: &Program) -> bool {
match self {
Self::Ref { inner, .. } => {
inner.is_numeric(program)
}
Self::Owned(name) => {
match program.types.get(&name) {
Some(t) => t.inner().is_numeric(program),
_ => false
}
},
Self::SizedArray { .. } => false,
Self::UnsizedArray { .. } => false,
Self::Builtin { name, .. } => {
match name.as_str() {
"u8" | "i8" |
"u16" | "i16" |
"u32" | "i32" |
"u64" | "i64" |
"usize" | "isize" => true,
_ => false,
}
}
}
}
pub fn is_ptr(&self, program: &Program) -> bool {
match self {
Self::Owned(name) => {
match program.types.get(&name) {
Some(t) => t.inner().is_ptr(program),
_ => false
}
},
Self::Ref { .. } => true,
_ => false
}
}
pub fn is_bool(&self, program: &Program) -> bool {
match self {
Self::Owned(name) => {
match program.types.get(&name) {
Some(t) => t.inner().is_bool(program),
_ => false
}
},
Self::Builtin { name, .. } if name.as_str() == "bool" => true,
_ => false
}
}
pub fn size_of(&self, program: &Program) -> anyhow::Result<usize> {
match self {
Self::Ref { inner, mutable } => {
Self::Ref { .. } => {
// TODO: Use the actual ptr size
Ok(size_of::<*const ()>())
}
@ -35,19 +107,15 @@ impl Type {
Self::SizedArray { inner, .. } => {
Ok(inner.size_of(program)? )
}
Self::Builtin { size, .. } => {
Ok(*size as usize)
}
Self::Owned(name) => {
if let Some(v) = program.structs.get(&name) {
return Ok(v.inner().get_size(program)?);
}
if let Some(v) = program.types.get(&name) {
match v {
TypeType::Normal(v) => {
return Ok(v.inner().size_of(program)?);
}
TypeType::Builtin { size, .. } => {
return Ok(*size);
}
}
return Ok(v.inner().size_of(program)?);
}
if let Some(_) = program.enums.get(&name) {
return Ok(4); // TODO: Make enum size changeable
@ -93,7 +161,10 @@ impl Display for Type {
_ => unreachable!()
}
}
Self::Owned(ident) => write!(f, "{ident}")
Self::Owned(ident) => write!(f, "{ident}"),
Self::Builtin { name, size, signed } => {
write!(f, "(builtin) {} {}({})", name, if *signed { "signed" } else { "unsigned" }, size)
}
}
}
}

View File

@ -1,8 +1,8 @@
use std::collections::HashMap;
use std::collections::{BTreeMap, HashMap};
use anyhow::{bail, Result};
use crate::{common::loc::LocBox, debug, error, lerror, parser::{typ::parse_type, Punctuation}, tokeniser::Token};
use crate::{common::loc::LocBox, debug, lerror, parser::{typ::parse_type, Punctuation}, tokeniser::Token};
use super::{ast::{expr::{Block, CallParams, Expr, IfBranchExpr, IfExpr, Path}, literal::Literal, TokenType}, parse_item, utils, Delimiter, Keyword};
@ -317,10 +317,15 @@ fn parse_literal(tokens: &mut Vec<Token>) -> Result<LocBox<Expr>> {
bail!("")
};
let count = parse_expr(tokens, 0, false)?.unwrap();
let Expr::Literal(Literal::Number(count)) = count.inner() else {
lerror!(count.loc(), "a repeating array accepts only literal numbers for count argument");
bail!("")
};
utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::SquareR), "")?;
return Ok(LocBox::new(start.loc(), Expr::Literal(Literal::ArrayRepeat {
val: Box::new(typ),
count: Box::new(count)
count: count.val
})));
} else {
if let Some(curr) = tokens.last() {
@ -336,7 +341,7 @@ fn parse_literal(tokens: &mut Vec<Token>) -> Result<LocBox<Expr>> {
fn parse_struct_literal(tokens: &mut Vec<Token>, name: Path) -> Result<LocBox<Expr>> {
let start = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::CurlyL), "")?;
let mut fields = HashMap::new();
let mut fields = BTreeMap::new();
while !tokens.is_empty() {
if let Some(_) = utils::check_consume(tokens, TokenType::Delim(Delimiter::CurlyR)) {
break;
@ -384,8 +389,8 @@ fn parse_path(tokens: &mut Vec<Token>) -> Result<LocBox<Expr>> {
fn parse_unop(tokens: &mut Vec<Token>) -> Result<LocBox<Expr>> {
let typ = utils::check_consume_or_err_from_many(tokens, &[
TokenType::Punct(Punctuation::Not),
TokenType::Punct(Punctuation::Plus),
TokenType::Punct(Punctuation::Minus),
TokenType::Punct(Punctuation::Plus), // Make number positive
TokenType::Punct(Punctuation::Minus), // make number negative
TokenType::Punct(Punctuation::Ampersand),
TokenType::Punct(Punctuation::Star),
], "")?;

View File

@ -32,7 +32,8 @@ pub fn parse_program(mut tokens: Vec<Token>) -> Result<Program> {
types: HashMap::new(),
structs: HashMap::new(),
static_vars: HashMap::new(),
const_vars: HashMap::new()
const_vars: HashMap::new(),
scope: None
})
}

View File

@ -3,6 +3,7 @@ use anyhow::bail;
use crate::common::loc::LocBox;
use crate::lerror;
use crate::parser::ast::TokenType;
use crate::parser::ast::statement::Let;
use crate::parser::expr::parse_expr;
use crate::parser::{Delimiter, Ident, Keyword, Punctuation};
use crate::tokeniser::Token;
@ -121,7 +122,7 @@ fn parse_let(tokens: &mut Vec<Token>) -> Result<LocBox<Statement>> {
val = Some(_val);
}
_ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), "")?;
Ok(LocBox::new(kw.loc(), Statement::Let { name, typ, val }))
Ok(LocBox::new(kw.loc(), Statement::Let(Let{ name, typ, val })))
}
fn parse_constant(tokens: &mut Vec<Token>) -> Result<LocBox<Statement>> {
let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Const), "")?;

View File

@ -1,6 +1,6 @@
use anyhow::Result;
use anyhow::{Result, bail};
use crate::{common::loc::LocBox, error, logger::log, parser::Delimiter, tokeniser::Token};
use crate::{common::loc::LocBox, lerror, parser::{Delimiter, ast::{expr::Expr, literal::Literal}}, tokeniser::Token};
use super::{ast::{typ::Type, TokenType}, expr::parse_expr, utils, Keyword, Punctuation};
@ -26,9 +26,18 @@ pub fn parse_type(tokens: &mut Vec<Token>) -> Result<LocBox<Type>> {
let itm_typ = parse_type(tokens)?;
if let Some(_) = utils::check_consume(tokens, TokenType::Punct(Punctuation::Semi)) {
let count = parse_expr(tokens, 0, false)?.unwrap();
match count.inner() {
Expr::Literal(Literal::Number(_)) |
Expr::Path(_) => (),
_ => {
lerror!(count.loc(), "Only literal numbers are allowed in sized arrays");
bail!("")
}
}
typ = Type::SizedArray {
inner: Box::new(itm_typ.inner().clone()),
count
count: count
};
} else {
typ = Type::UnsizedArray {

View File

@ -2,7 +2,7 @@ use std::{fs::File, path::{Path, PathBuf}};
use crate::{cli::CliArgs, parser::ast::Program};
mod x86_64;
mod none;
//mod none;
pub fn get_default_target() -> String {
x86_64::cgen::linux::CGen::get_target_triple().to_string()
@ -13,7 +13,7 @@ pub fn get_all_targets() -> Vec<&'static str> {
// x86_64::asmgen::linux::AsmGen::get_target_triple(),
// x86_64::cgen::linux::CGen::get_target_triple(),
// x86_64::llvmgen::linux::LlvmGen::get_target_triple(),
none::luagen::cct::LuaGen::get_target_triple(),
//none::luagen::cct::LuaGen::get_target_triple(),
x86_64::cgen::linux::CGen::get_target_triple(),
]
}

View File

@ -1,6 +1,6 @@
use std::{fs::File, ops::Deref};
use std::io::Write;
use crate::{common::Loc, parser::ast::{expr::Expr, literal::Literal, statement::{Function, Statement, Struct}, typ::Type, Ast, Ident, Program, Punctuation}, targets::Target, validator::predefined::TypeType};
use crate::{common::Loc, parser::ast::{expr::Expr, literal::Literal, statement::{Function, Statement, Struct}, typ::Type, Ast, Ident, Program, Punctuation}, targets::Target};
const INTERNAL_CODE: &'static str = include_str!("internals.c");
@ -19,8 +19,8 @@ impl Target for CGen {
fn write_code(&mut self, program: &crate::parser::ast::Program, f: &mut File) -> anyhow::Result<()> {
self.write_fat_comment(f, "Internal number types");
for (name, typ) in &program.types {
if let TypeType::Builtin { size: _, signed: _ } = typ {
self.write_internal_type(f, program, name, typ)?;
if let Type::Builtin { name: _, size: _, signed: _ } = typ.inner() {
self.write_internal_type(f, program, name, typ.inner())?;
}
}
@ -34,9 +34,7 @@ impl Target for CGen {
self.write_fat_comment(f, "Type aliases");
for (name, typ) in &program.types {
if let TypeType::Normal(t) = typ {
self.write_typedef(f, program, t.inner(), name)?;
}
self.write_typedef(f, program, typ.inner(), name)?;
}
self.write_fat_comment(f, "Struct definitions");
@ -45,7 +43,7 @@ impl Target for CGen {
}
self.write_fat_comment(f, "Function forward declarations");
fn write_fn_fwdclr(slf: &mut CGen, program: &Program, f: &mut File, name: &Ident, func: &Function) -> anyhow::Result<()> {
fn write_fn_fwdclr(slf: &mut CGen, program: &Program, f: &mut File, _name: &Ident, func: &Function) -> anyhow::Result<()> {
writeln!(f, "// {}", func.get_def_as_str())?;
if let Some(rett) = &func.ret_type {
slf.write_type(f, program, rett.inner())?;
@ -121,7 +119,7 @@ impl CGen {
Expr::If(_ifexpr) => {
}
Expr::BinOp { typ, left, right } => {
Expr::BinOp { typ, .. } => {
match typ {
Punctuation::Eq => {
@ -182,6 +180,7 @@ impl CGen {
pf.push_str(&part(f, program, inner)?);
pf.push_str("[]");
}
Type::Builtin { .. } => ()
}
Ok(pf)
}
@ -223,14 +222,14 @@ impl CGen {
write!(f, "[]")?;
}
}
Type::Builtin { .. } => ()
}
Ok(())
}
fn write_internal_type(&mut self, f: &mut File, program: &Program, name: &Ident, typ: &TypeType) -> anyhow::Result<()> {
fn write_internal_type(&mut self, f: &mut File, _program: &Program, _name: &Ident, typ: &Type) -> anyhow::Result<()> {
match typ {
TypeType::Normal(typ) => unreachable!(),
TypeType::Builtin{ size, signed } => {
Type::Builtin{ name, size, signed } => {
if *size == 0 {
return Ok(());
}
@ -249,7 +248,7 @@ impl CGen {
8 => write!(f, "long long ")?,
3 | 5 | 6 | 7 => unreachable!(),
}
writeln!(f, "{};", name.0)?;
writeln!(f, "{};", name)?;
}
_ => (),
}
@ -267,7 +266,7 @@ impl CGen {
Ok(())
}
fn write_fn(&mut self, f: &mut File, program: &Program, func: &Function, loc: &Loc) -> anyhow::Result<()> {
fn write_fn(&mut self, f: &mut File, program: &Program, func: &Function, _loc: &Loc) -> anyhow::Result<()> {
writeln!(f, "\n\n// {}", func.get_def_as_str())?;
if let Some(rett) = &func.ret_type {
self.write_type(f, program, rett.inner())?;
@ -295,7 +294,7 @@ impl CGen {
Ast::Expr(expr) => {
self.write_expr(f, program, expr.inner(), expr.loc())?
}
Ast::Statement(stat) => {
Ast::Statement(_) => {
//todo!()
}
}

View File

@ -1,7 +1,7 @@
use std::{collections::HashMap, fmt::Display};
use anyhow::bail;
use parse_int::parse;
use crate::{common::{loc::LocIncr, Loc}, error, lerror};
use crate::{common::{loc::LocIncr, Loc},lerror};
pub mod tokentype;
use tokentype::*;

View File

@ -1,6 +1,8 @@
use core::panic;
use std::fmt::Display;
use crate::parser::ast::expr::Path;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Ident(pub String);
@ -10,6 +12,12 @@ impl Display for Ident {
}
}
impl Ident {
pub fn as_path(self) -> Path {
Path(vec![self])
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Number {

View File

@ -0,0 +1,59 @@
use anyhow::bail;
use crate::{common::loc::LocBox, parser::ast::{Ast, Program, expr::Expr, statement::Statement}, validator::validate_expr};
pub fn calc(prog: &mut Program) -> anyhow::Result<()> {
let mut body = prog.ast.0.clone();
for item in body.iter_mut() {
calc_ast(prog, item)?;
}
prog.ast.0 = body;
Ok(())
}
pub fn calc_ast(prog: &mut Program, ast: &mut Ast) -> anyhow::Result<()> {
match ast {
Ast::Statement(stat) => calc_stat(prog, stat.inner_mut())?,
Ast::Expr(expr) => calc_expr(prog, expr.inner_mut())?,
}
Ok(())
}
pub fn calc_stat(prog: &mut Program, stat: &mut Statement) -> anyhow::Result<()> {
match stat {
Statement::Fn(func) => {
if let Some(body) = &mut func.body {
for item in &mut body.0 {
calc_ast(prog, item)?;
}
}
}
Statement::Let(lt) => {
match (lt.typ.clone(), lt.val.clone()) {
(None, None) => {
}
(None, Some(val)) => {
let Some(t) = validate_expr(prog, val.inner())? else {
lerror!(val.loc(), "Expected a type, go none");
bail!("");
};
lt.typ = Some(LocBox::new(val.loc(), t));
}
_ => ()
}
}
_ => ()
}
Ok(())
}
pub fn calc_expr(_prog: &mut Program, _expr: &mut Expr) -> anyhow::Result<()> {
Ok(())
}

View File

@ -1,14 +1,11 @@
use std::collections::HashMap;
use anyhow::{anyhow, bail};
use anyhow::bail;
use crate::{common::{loc::LocBox, Loc}, parser::ast::{expr::{Block, Expr}, statement::{Statement, TypeAlias}, typ::Type, Ast, Program}};
use crate::{common::{Loc, loc::LocBox}, parser::ast::{Ast, Program, Punctuation, TokenType, expr::*, statement::*, typ::Type}};
pub mod predefined;
struct Scope {
}
pub mod calculate_types;
pub fn validate_code(prog: &mut Program) -> anyhow::Result<()> {
let Block(items) = prog.ast.clone();
@ -20,24 +17,9 @@ pub fn validate_code(prog: &mut Program) -> anyhow::Result<()> {
//dbg!(&prog.enums);
//dbg!(&prog.member_functions);
//dbg!(&prog.functions);
for item in items {
for item in items.iter() {
match item {
Ast::Statement(stat) => {
match stat.inner() {
Statement::Fn(func) => {}
Statement::Let { .. } => {
lerror!(stat.loc(), "Let statements are not allowed outside a function");
bail!("")
}
Statement::ConstVar(var) => {
}
Statement::StaticVar(var) => {
}
Statement::Enum(enm) => {}
Statement::Struct(strct) => {}
Statement::TypeAlias(alias) => {}
}
}
Ast::Statement(stat) => validate_stat(prog, &stat, CurrentState::Outside)?,
Ast::Expr(_) => unreachable!()
}
}
@ -46,6 +28,410 @@ pub fn validate_code(prog: &mut Program) -> anyhow::Result<()> {
Ok(())
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
enum CurrentState {
InFunc,
Outside,
}
fn validate_stat(prog: &mut Program, stat: &LocBox<Statement>, current_state: CurrentState) -> anyhow::Result<()> {
match stat.inner() {
Statement::Fn(func) => validate_fn(prog, &func)?,
Statement::Let(lt) if current_state == CurrentState::InFunc => validate_stat_let(prog, lt)?,
Statement::Let(_) if current_state == CurrentState::Outside => {
lerror!(stat.loc(), "Let statements are not allowed outside a function");
bail!("")
}
Statement::ConstVar(var) => validate_const_var(prog, var)?,
Statement::StaticVar(var) => validate_static_var(prog, var)?,
Statement::Enum(enm) => validate_enum(prog, enm)?,
Statement::Struct(strct) => validate_struct(prog, strct)?,
Statement::TypeAlias(alias) => validate_type_alias(prog, alias)?,
Statement::Let(_) => unreachable!()
}
Ok(())
}
fn validate_stat_let(prog: &mut Program, lt: &Let) -> anyhow::Result<()> {
if let Some(val) = &lt.val && let Some(t) = &lt.typ {
let val_t = validate_expr(prog, &val.inner())?.unwrap();
if val_t != *t.inner() {
lerror!(t.loc(), "Cannot assign {val_t} to {}", t.inner());
bail!("")
}
}
Ok(())
}
fn validate_ast(prog: &mut Program, ast: &Ast) -> anyhow::Result<Option<Type>> {
match ast {
Ast::Expr(expr) => {
validate_expr(prog, &expr.inner())
}
Ast::Statement(stat) => {
validate_stat(prog, &stat, CurrentState::InFunc)?;
Ok(None)
}
}
}
pub fn validate_expr(prog: &mut Program, expr: &Expr) -> anyhow::Result<Option<Type>> {
match expr {
Expr::Break | Expr::Continue => Ok(None),
Expr::Return(ret) => {
if let Some(expr) = &**ret {
validate_expr(prog, expr.inner())
} else {
Ok(None)
}
}
Expr::Struct { path, fields } => {
// this is probably fucked so fix this later
let name = path.0.last().expect("Paths always have at least one part");
let typ = Type::Owned(name.clone());
// this is so ass, this checks if struct exists
validate_type(prog, &LocBox::new(&Loc::default(), typ.clone()))?;
for field in fields {
validate_expr(prog, &field.1.inner())?;
}
Ok(Some(typ))
},
Expr::If(ifs) => {
validate_expr(prog, ifs.test.inner())?;
for item in &ifs.body.0 {
validate_ast(prog, item)?;
}
Ok(None)
}
Expr::Path(path) => {
// TODO: Path hell TBD
Ok(Some(Type::Owned(path.0.last().unwrap().clone())))
}
Expr::Group(group) => validate_expr(prog, &group.inner()),
Expr::Call { path, params } => {
let loc = path.loc();
let Expr::Path(path) = path.inner() else {
panic!("fml");
};
let func;
match path.0.len() {
1 => {
let f = prog.functions.get(&path.0[0]);
match f {
Some(f) => func = f.clone(),
None => {
lerror!(loc, "Could not find function {}", path);
panic!("")
}
}
}
2 => {
let s = prog.member_functions.get(&path.0[0]).unwrap();
let f = s.get(&path.0[1]);
match f {
Some(f) => func = LocBox::new(loc, f.clone().inner().clone()),
None => {
lerror!(loc, "Could not find function {}", path);
panic!("")
}
}
}
_ => panic!("")
}
for (i, param) in params.0.iter().enumerate() {
let t = validate_expr(prog, param.inner())?;
let ft = func.inner().params[i].1.inner();
if t.as_ref() != Some(ft) {
lerror!(param.loc(), "expected {ft}, got {}", t.unwrap());
bail!("")
}
}
if let Some(t) = &func.inner().ret_type {
Ok(Some(t.inner().clone()))
} else {
Ok(None)
}
}
Expr::ForLoop { init, test, on_loop, body } => {
let _ = validate_ast(prog, init)?;
let _ = validate_expr(prog, test.inner())?;
let _ = validate_expr(prog, on_loop.inner())?;
for item in &body.0 {
let _ = validate_ast(prog, item)?;
}
Ok(None)
},
Expr::Cast { left, right } => {
validate_expr(prog, left.inner())?;
Ok(Some(right.inner().clone()))
}
Expr::Literal(lit) => {
Ok(Some(lit.to_type(prog)?))
}
Expr::UnOp { typ, right } => {
match typ {
Punctuation::Not => {
let t = validate_expr(prog, right.inner())?.unwrap();
if !t.is_bool(prog) {
lerror!(right.loc(), "Expected bool, got {t}");
}
Ok(Some(t))
}
Punctuation::Minus |
Punctuation::Plus => {
let t = validate_expr(prog, right.inner())?.unwrap();
if !t.is_numeric(prog) {
lerror!(right.loc(), "Expected number, got {t}");
}
Ok(Some(t))
}
Punctuation::Ampersand => {
let t = validate_expr(prog, right.inner())?.unwrap();
Ok(Some(Type::Ref { inner: Box::new(t), mutable: false }))
}
Punctuation::Star => {
let t = validate_expr(prog, right.inner())?.unwrap();
if !t.is_ptr(prog) {
lerror!(right.loc(), "Expected pointer, got {t}");
}
match t {
Type::Ref { inner, .. } => Ok(Some(*inner)),
_ => unreachable!()
}
}
_ => unreachable!()
}
},
Expr::BinOp { typ, left, right } => {
match typ {
Punctuation::Ampersand |
Punctuation::Or |
Punctuation::Xor |
Punctuation::Plus |
Punctuation::Minus |
Punctuation::Div |
Punctuation::Star |
Punctuation::Mod |
Punctuation::Shl |
Punctuation::Shr => {
let t1_s;
let t2_s;
let t1 = validate_expr(prog, left.inner())?.unwrap();
let t2 = validate_expr(prog, right.inner())?.unwrap();
if !t1.is_numeric(prog) {
lerror!(right.loc(), "Expected bool, got {t1}");
}
if !t2.is_numeric(prog) {
lerror!(right.loc(), "Expected bool, got {t2}");
}
match &t1 {
Type::Builtin { name: _, size, .. } => t1_s = *size,
_ => unreachable!()
}
match &t2 {
Type::Builtin { name: _, size, .. } => t2_s = *size,
_ => unreachable!()
}
if t2_s > t1_s {
Ok(Some(t2))
} else {
Ok(Some(t1))
}
}
Punctuation::EqEq |
Punctuation::Lt |
Punctuation::Gt |
Punctuation::Le |
Punctuation::Ge |
Punctuation::AndAnd |
Punctuation::OrOr => {
let t1 = validate_expr(prog, left.inner())?.unwrap();
let t2 = validate_expr(prog, right.inner())?.unwrap();
if !t1.is_bool(prog) {
lerror!(right.loc(), "Expected bool, got {t1}");
}
if !t2.is_bool(prog) {
lerror!(right.loc(), "Expected bool, got {t2}");
}
Ok(Some(t1))
}
Punctuation::AddEq |
Punctuation::SubEq |
Punctuation::DivEq |
Punctuation::MulEq |
Punctuation::ModEq |
Punctuation::ShlEq |
Punctuation::ShrEq |
Punctuation::AndEq |
Punctuation::OrEq |
Punctuation::XorEq => {
let var = validate_expr(prog, left.inner())?.unwrap();
let var_t = var.get_absolute_value(prog)?;
let val_t = validate_expr(prog, right.inner())?.unwrap();
if !(var_t.is_numeric(prog) && val_t.is_numeric(prog)) {
lerror!(left.loc(), "Mismatched types, assigning {val_t} to {var_t}");
bail!("");
}
Ok(None)
}
Punctuation::Eq => {
let var = validate_expr(prog, left.inner())?.unwrap();
let var_t = var.get_absolute_value(prog)?;
let val_t = validate_expr(prog, right.inner())?.unwrap();
if !(var_t == val_t || var_t.is_numeric(prog) && val_t.is_numeric(prog)) {
lerror!(left.loc(), "Mismatched types, assigning {val_t} to {var_t}");
bail!("");
}
Ok(None)
}
_ => unreachable!()
}
},
Expr::ArrayIndex { name, index } => {
let left = validate_expr(prog, name.inner())?;
let Some(left) = left else {
lerror!(name.loc(), "expected value, got nothing, cannot index nothing");
bail!("")
};
fn f(prog: &mut Program, left: &Type, loc: &Loc, index: &LocBox<Expr>) -> anyhow::Result<Option<Type>> {
match left {
Type::SizedArray { inner, count } => {
let val1 = count.inner().as_number(prog).unwrap();
let val2 = index.inner().as_number(prog).unwrap();
if val1.signed && (val1.val as isize) < 0 {
lerror!(index.loc(), "Cannot index bellow 0");
bail!("");
}
if val1.val <= val2.val {
lerror!(index.loc(), "Cannot index outside aray boundaries");
bail!("");
}
Ok(Some(*inner.clone()))
}
Type::UnsizedArray { inner } => {
Ok(Some(*inner.clone()))
}
Type::Owned(name) => {
let t = prog.types.get(name).cloned();
if let Some(t) = t {
f(prog, t.inner(), t.loc(), index)
} else {
lerror!(loc, "Unknown type {name}");
bail!("")
}
}
Type::Ref { .. } |
Type::Builtin { .. } => {
lerror!(loc, "Numeric, pointer, and void types are not indexable (TODO: Maybe allow indexing pointers?)");
bail!("")
}
}
}
f(prog, &left, name.loc(), &index)
},
Expr::PtrFieldAccess { left, right } |
Expr::FieldAccess { left, right } => {
let left = validate_expr(prog, left.clone().unwrap().inner())?;
let right = validate_expr(prog, right.clone().inner())?.unwrap();
let Type::Owned(right) = right else {
panic!()
};
match left.unwrap() {
Type::Owned(name) => {
if let Some(strct) = prog.structs.get(&name) {
for field in &strct.inner().fields {
if field.0 == right {
return Ok(Some(field.1.inner().clone()));
}
}
}
}
_ => panic!()
}
Ok(None)
},
Expr::WhileLoop { test, body } => {
let _ = validate_expr(prog, test.inner())?;
for item in &body.0 {
let _ = validate_ast(prog, item)?;
}
Ok(None)
},
Expr::InfLoop { body } => {
for item in &body.0 {
let _ = validate_ast(prog, item)?;
}
Ok(None)
}
}
}
fn validate_fn(prog: &mut Program, func: &Function) -> anyhow::Result<()> {
for param in &func.params {
validate_type(prog, &param.1)?;
}
if let Some(body) = &func.body {
for item in &body.0 {
validate_ast(prog, item)?;
}
}
Ok(())
}
fn validate_const_var(prog: &mut Program, var: &ConstVar) -> anyhow::Result<()> {
validate_type(prog, &var.typ)?;
Ok(())
}
fn validate_static_var(prog: &mut Program, var: &StaticVar) -> anyhow::Result<()> {
validate_type(prog, &var.typ)?;
Ok(())
}
fn validate_enum(_: &mut Program, _: &Enum) -> anyhow::Result<()> {
// Enum has no actual types
Ok(())
}
fn validate_struct(prog: &mut Program, strct: &Struct) -> anyhow::Result<()> {
for field in &strct.fields {
if let Err(e) = validate_type(prog, &field.1) {
error!("Could not find type in field {}::{}", strct.name, field.0);
anyhow::bail!(e);
}
}
Ok(())
}
fn validate_type_alias(prog: &mut Program, alias: &TypeAlias) -> anyhow::Result<()> {
validate_type(prog, &alias.typ)?;
Ok(())
}
fn check_that_types_exist_for_items(prog: &mut Program, items: &Vec<Ast>) -> anyhow::Result<()> {
let mut errored = false;
for item in items {
@ -116,10 +502,11 @@ fn validate_type(prog: &mut Program, typ: &LocBox<Type>) -> anyhow::Result<()> {
prog.structs.get(typ).is_some() {
Ok(())
} else {
// lerror!(loc, "Could not find type '{}'", typ.0);
lerror!(loc, "Could not find type '{}'", typ.0);
bail!("")
}
}
Type::Builtin { .. } => Ok(())
}
}
f(prog, typ.inner(), typ.loc())
@ -153,7 +540,7 @@ fn collect_types_and_constants(prog: &mut Program, items: &Vec<Ast>) {
}
Statement::TypeAlias(alias) => {
let typ = alias.clone().typ.inner().clone();
prog.types.insert(alias.name.clone(), predefined::TypeType::Normal(LocBox::new(stat.loc(), typ)));
prog.types.insert(alias.name.clone(), LocBox::new(stat.loc(), typ));
}
Statement::Let { .. } => (),
Statement::ConstVar(var) => {

View File

@ -1,13 +1,14 @@
use std::collections::HashMap;
use lazy_static::lazy_static;
use crate::common::Loc;
use crate::parser::ast::expr::Path;
use crate::parser::typ::parse_type;
use crate::{common::loc::LocBox, parser::ast::{statement::Function, typ::Type, Ident, Program}};
#[cfg(target_arch="x86_64")]
const SIZE: usize = 8;
pub const SIZE: usize = 8;
#[cfg(target_arch="x86")]
const SIZE: usize = 4;
pub const SIZE: usize = 4;
lazy_static!(
pub static ref TYPES_RAW: HashMap<&'static str, (usize, bool)> = [
@ -22,6 +23,7 @@ lazy_static!(
("i16", (2, true)),
("i32", (4, true)),
("i64", (8, true)),
("bool", (1, true)),
].into();
pub static ref FUNCTIONS: HashMap<&'static str, (Vec<(&'static str, &'static str)>, &'static str)> = [
("syscall", (vec![
@ -32,18 +34,14 @@ lazy_static!(
].into();
);
#[derive(Debug, Clone)]
pub enum TypeType {
Normal(LocBox<Type>),
Builtin {
size: usize,
signed: bool,
}
}
pub fn load_builtin(prog: &mut Program) {
let loc = Loc::new("(internal)", 0, 0);
for (name, (size, signed)) in TYPES_RAW.iter() {
prog.types.insert(Ident(name.to_string()), TypeType::Builtin{ size: *size, signed: *signed });
prog.types.insert(
Ident(name.to_string()),
LocBox::new(&loc, Type::Builtin{ name: name.to_string(), size: *size as u8, signed: *signed })
);
}
for (name, (args, ret_typ)) in FUNCTIONS.iter() {