Compare commits
No commits in common. "1f4645ed2483c75bc29a61f7c590a305906e9ce4" and "06d8c1b0f3e9fcdde86a6983b42b5493a232d3f5" have entirely different histories.
1f4645ed24
...
06d8c1b0f3
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "mclangc"
|
name = "mclangc"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2021"
|
||||||
default-run = "mclangc"
|
default-run = "mclangc"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ impl Loc {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct LocBox<T: Clone + Debug> {
|
pub struct LocBox<T: Clone + Debug> {
|
||||||
inner: T,
|
inner: T,
|
||||||
loc: Loc
|
loc: Loc
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ pub mod log {
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! lerror {
|
macro_rules! lerror {
|
||||||
($loc:expr_2021, $($arg:tt)*) => {
|
($loc:expr, $($arg:tt)*) => {
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
crate::logger::_log_with_loc(Some((file!(), line!(), column!())), format!("{}", $loc), crate::logger::Level::Error, &format!($($arg)*))
|
crate::logger::_log_with_loc(Some((file!(), line!(), column!())), format!("{}", $loc), crate::logger::Level::Error, &format!($($arg)*))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -120,7 +120,7 @@ pub mod log {
|
||||||
}
|
}
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! lwarn {
|
macro_rules! lwarn {
|
||||||
($loc:expr_2021, $($arg:tt)*) => {
|
($loc:expr, $($arg:tt)*) => {
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
crate::logger::_log_with_loc(Some((file!(), line!(), column!())), format!("{}", $loc), crate::logger::Level::Warn, &format!($($arg)*))
|
crate::logger::_log_with_loc(Some((file!(), line!(), column!())), format!("{}", $loc), crate::logger::Level::Warn, &format!($($arg)*))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -130,7 +130,7 @@ pub mod log {
|
||||||
}
|
}
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! linfo {
|
macro_rules! linfo {
|
||||||
($loc:expr_2021, $($arg:tt)*) => {
|
($loc:expr, $($arg:tt)*) => {
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
crate::logger::_log_with_loc(Some((file!(), line!(), column!())), format!("{}", $loc), crate::logger::Level::Info, &format!($($arg)*))
|
crate::logger::_log_with_loc(Some((file!(), line!(), column!())), format!("{}", $loc), crate::logger::Level::Info, &format!($($arg)*))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -140,7 +140,7 @@ pub mod log {
|
||||||
}
|
}
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! lhelp {
|
macro_rules! lhelp {
|
||||||
($loc:expr_2021, $($arg:tt)*) => {
|
($loc:expr, $($arg:tt)*) => {
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
crate::logger::_log_with_loc(Some((file!(), line!(), column!())), format!("{}", $loc), crate::logger::Level::Help, &format!($($arg)*))
|
crate::logger::_log_with_loc(Some((file!(), line!(), column!())), format!("{}", $loc), crate::logger::Level::Help, &format!($($arg)*))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -150,7 +150,7 @@ pub mod log {
|
||||||
}
|
}
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! ldebug {
|
macro_rules! ldebug {
|
||||||
($loc:expr_2021, $($arg:tt)*) => {
|
($loc:expr, $($arg:tt)*) => {
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
crate::logger::_log_with_loc(Some((file!(), line!(), column!())), format!("{}", $loc), crate::logger::Level::Debug, &format!($($arg)*))
|
crate::logger::_log_with_loc(Some((file!(), line!(), column!())), format!("{}", $loc), crate::logger::Level::Debug, &format!($($arg)*))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ fn main() -> anyhow::Result<()> {
|
||||||
info!("Parsing {file}");
|
info!("Parsing {file}");
|
||||||
let mut prog = mclangc::parser::parse_program(tokens)?;
|
let mut prog = mclangc::parser::parse_program(tokens)?;
|
||||||
info!("Validating {file}");
|
info!("Validating {file}");
|
||||||
dbg!(&prog);
|
|
||||||
mclangc::validator::validate_code(&mut prog)?;
|
mclangc::validator::validate_code(&mut prog)?;
|
||||||
// dbg!(&prog);
|
// dbg!(&prog);
|
||||||
progs.push((fp, prog));
|
progs.push((fp, prog));
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
use std::{collections::BTreeMap, fmt::Display};
|
use std::{collections::HashMap, fmt::Display};
|
||||||
|
|
||||||
use crate::{common::loc::LocBox, parser::ast::{Program, literal::Literal}, tokeniser::tokentype::*};
|
use crate::{common::loc::LocBox, tokeniser::tokentype::*};
|
||||||
|
|
||||||
use super::{typ::Type, Ast};
|
use super::{typ::Type, Ast};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
// Comment(Comment),
|
// Comment(Comment),
|
||||||
Group(Box<LocBox<Expr>>),
|
Group(Box<LocBox<Expr>>),
|
||||||
|
|
@ -58,7 +58,7 @@ pub enum Expr {
|
||||||
If(IfExpr),
|
If(IfExpr),
|
||||||
Struct {
|
Struct {
|
||||||
path: Path,
|
path: Path,
|
||||||
fields: BTreeMap<Ident, LocBox<Expr>>,
|
fields: HashMap<Ident, LocBox<Expr>>,
|
||||||
},
|
},
|
||||||
Return(Box<Option<LocBox<Expr>>>),
|
Return(Box<Option<LocBox<Expr>>>),
|
||||||
Break,
|
Break,
|
||||||
|
|
@ -74,30 +74,17 @@ impl Expr {
|
||||||
let Expr::Path(p) = self else {panic!("Unwrapping")};
|
let Expr::Path(p) = self else {panic!("Unwrapping")};
|
||||||
p.clone()
|
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, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CallParams(pub Vec<LocBox<Expr>>);
|
pub struct CallParams(pub Vec<LocBox<Expr>>);
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Block(pub Vec<Ast>);
|
pub struct Block(pub Vec<Ast>);
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Hash)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Path(pub Vec<Ident>);
|
pub struct Path(pub Vec<Ident>);
|
||||||
|
|
||||||
impl Display for Path {
|
impl Display for Path {
|
||||||
|
|
@ -113,14 +100,14 @@ impl Display for Path {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct IfExpr {
|
pub struct IfExpr {
|
||||||
pub test: Box<LocBox<Expr>>,
|
pub test: Box<LocBox<Expr>>,
|
||||||
pub body: Block,
|
pub body: Block,
|
||||||
pub else_if: Option<IfBranchExpr>
|
pub else_if: Option<IfBranchExpr>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum IfBranchExpr {
|
pub enum IfBranchExpr {
|
||||||
ElseIf(Box<IfExpr>),
|
ElseIf(Box<IfExpr>),
|
||||||
Else(Block)
|
Else(Block)
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{common::{Loc, loc::LocBox}, parser::ast::{Program, typ::Type}, tokeniser::tokentype::*, validator::{predefined::SIZE, validate_expr}};
|
use crate::{common::loc::LocBox, tokeniser::tokentype::*};
|
||||||
|
|
||||||
use super::expr::Expr;
|
use super::{expr::Expr, typ::Type, Ast};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Literal {
|
pub enum Literal {
|
||||||
Number(Number),
|
Number(Number),
|
||||||
Ident(Ident),
|
Ident(Ident),
|
||||||
|
|
@ -12,36 +13,6 @@ pub enum Literal {
|
||||||
Array(Vec<LocBox<Expr>>),
|
Array(Vec<LocBox<Expr>>),
|
||||||
ArrayRepeat {
|
ArrayRepeat {
|
||||||
val: Box<LocBox<Expr>>,
|
val: Box<LocBox<Expr>>,
|
||||||
count: usize,
|
count: Box<LocBox<Expr>>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
use statement::{ConstVar, Enum, Function, StaticVar, Struct};
|
use statement::{ConstVar, Enum, Function, StaticVar, Struct};
|
||||||
|
|
||||||
use crate::{common::loc::LocBox, parser::ast::{expr::Path, statement::Let, typ::Type}};
|
use crate::{common::loc::LocBox, validator::predefined::TypeType};
|
||||||
pub use crate::tokeniser::tokentype::*;
|
pub use crate::tokeniser::tokentype::*;
|
||||||
|
|
||||||
pub mod expr;
|
pub mod expr;
|
||||||
|
|
@ -10,99 +10,19 @@ pub mod literal;
|
||||||
pub mod statement;
|
pub mod statement;
|
||||||
pub mod typ;
|
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)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Program {
|
pub struct Program {
|
||||||
pub ast: expr::Block,
|
pub ast: expr::Block,
|
||||||
pub structs: HashMap<Ident, LocBox<Struct>>,
|
pub structs: HashMap<Ident, LocBox<Struct>>,
|
||||||
pub enums: HashMap<Ident, LocBox<Enum>>,
|
pub enums: HashMap<Ident, LocBox<Enum>>,
|
||||||
pub types: HashMap<Ident, LocBox<Type>>,
|
pub types: HashMap<Ident, TypeType>,
|
||||||
pub functions: HashMap<Ident, LocBox<Function>>,
|
pub functions: HashMap<Ident, LocBox<Function>>,
|
||||||
pub member_functions: HashMap<Ident, HashMap<Ident, LocBox<Function>>>,
|
pub member_functions: HashMap<Ident, HashMap<Ident, LocBox<Function>>>,
|
||||||
pub static_vars: HashMap<Ident, StaticVar>,
|
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 {
|
pub enum Ast {
|
||||||
Expr(LocBox<expr::Expr>),
|
Expr(LocBox<expr::Expr>),
|
||||||
Statement(LocBox<statement::Statement>),
|
Statement(LocBox<statement::Statement>),
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use anyhow::bail;
|
use anyhow::bail;
|
||||||
|
|
||||||
use crate::{common::loc::LocBox, lerror, parser::ast::expr::Path};
|
use crate::{common::{loc::LocBox, Loc}, lerror};
|
||||||
|
|
||||||
use super::{expr::{Block, Expr}, literal::Literal, typ::Type, Char, Ident, Number, Program, TString};
|
use super::{expr::{Block, Expr}, literal::Literal, typ::Type, Char, Ident, Number, Program, TString};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Statement {
|
pub enum Statement {
|
||||||
Fn(Function),
|
Fn(Function),
|
||||||
TypeAlias(TypeAlias),
|
TypeAlias(TypeAlias),
|
||||||
|
|
@ -14,49 +15,46 @@ pub enum Statement {
|
||||||
Enum(Enum),
|
Enum(Enum),
|
||||||
ConstVar(ConstVar),
|
ConstVar(ConstVar),
|
||||||
StaticVar(StaticVar),
|
StaticVar(StaticVar),
|
||||||
Let(Let),
|
Let {
|
||||||
|
name: Ident,
|
||||||
|
typ: Option<LocBox<Type>>,
|
||||||
|
val: Option<LocBox<Expr>>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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 struct ConstVar {
|
||||||
pub name: Ident,
|
pub name: Ident,
|
||||||
pub typ: LocBox<Type>,
|
pub typ: LocBox<Type>,
|
||||||
pub val: LocBox<Expr>,
|
pub val: LocBox<Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct StaticVar {
|
pub struct StaticVar {
|
||||||
pub name: Ident,
|
pub name: Ident,
|
||||||
pub typ: LocBox<Type>,
|
pub typ: LocBox<Type>,
|
||||||
pub val: LocBox<Expr>,
|
pub val: LocBox<Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct TypeAlias {
|
pub struct TypeAlias {
|
||||||
pub name: Ident,
|
pub name: Ident,
|
||||||
pub typ: LocBox<Type>,
|
pub typ: LocBox<Type>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Struct {
|
pub struct Struct {
|
||||||
pub name: Ident,
|
pub name: Ident,
|
||||||
pub fields: Vec<(Ident, LocBox<Type>)>,
|
pub fields: Vec<(Ident, LocBox<Type>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Enum {
|
pub struct Enum {
|
||||||
pub name: Ident,
|
pub name: Ident,
|
||||||
pub fields: Vec<Ident>,
|
pub fields: Vec<Ident>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
pub struct_name: Option<Ident>,
|
pub struct_name: Option<Ident>,
|
||||||
pub name: Ident,
|
pub name: Ident,
|
||||||
|
|
@ -125,7 +123,7 @@ impl Struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ConstDataTyp {
|
pub enum ConstDataTyp {
|
||||||
Byte(u8),
|
Byte(u8),
|
||||||
AddrOfConst(Ident),
|
AddrOfConst(Ident),
|
||||||
|
|
@ -191,18 +189,7 @@ pub fn get_constant_data_as_bytes(program: &Program, value: LocBox<Expr>, is_lit
|
||||||
bail!("")
|
bail!("")
|
||||||
}
|
}
|
||||||
let mut val = get_constant_data_as_bytes(program, (**val).clone(), is_little_endian, must_be_number)?;
|
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;
|
let mut count = 0 as usize;
|
||||||
for b in num {
|
for b in num {
|
||||||
let ConstDataTyp::Byte(b) = b else {unreachable!()};
|
let ConstDataTyp::Byte(b) = b else {unreachable!()};
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,11 @@ use std::fmt::Display;
|
||||||
|
|
||||||
use anyhow::bail;
|
use anyhow::bail;
|
||||||
|
|
||||||
use crate::common::loc::LocBox;
|
use crate::{common::{loc::LocBox, Loc}, logger::log, validator::predefined::TypeType};
|
||||||
|
|
||||||
use super::{expr::Expr, literal::Literal, Ident, Program};
|
use super::{expr::Expr, literal::Literal, Ident, Program};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
Ref {
|
Ref {
|
||||||
inner: Box<Type>,
|
inner: Box<Type>,
|
||||||
|
|
@ -20,84 +20,12 @@ pub enum Type {
|
||||||
inner: Box<Type>,
|
inner: Box<Type>,
|
||||||
},
|
},
|
||||||
Owned(Ident),
|
Owned(Ident),
|
||||||
Builtin {
|
|
||||||
name: String,
|
|
||||||
size: u8,
|
|
||||||
signed: bool,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Type {
|
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> {
|
pub fn size_of(&self, program: &Program) -> anyhow::Result<usize> {
|
||||||
match self {
|
match self {
|
||||||
Self::Ref { .. } => {
|
Self::Ref { inner, mutable } => {
|
||||||
// TODO: Use the actual ptr size
|
// TODO: Use the actual ptr size
|
||||||
Ok(size_of::<*const ()>())
|
Ok(size_of::<*const ()>())
|
||||||
}
|
}
|
||||||
|
|
@ -107,16 +35,20 @@ impl Type {
|
||||||
Self::SizedArray { inner, .. } => {
|
Self::SizedArray { inner, .. } => {
|
||||||
Ok(inner.size_of(program)? )
|
Ok(inner.size_of(program)? )
|
||||||
}
|
}
|
||||||
Self::Builtin { size, .. } => {
|
|
||||||
Ok(*size as usize)
|
|
||||||
}
|
|
||||||
Self::Owned(name) => {
|
Self::Owned(name) => {
|
||||||
if let Some(v) = program.structs.get(&name) {
|
if let Some(v) = program.structs.get(&name) {
|
||||||
return Ok(v.inner().get_size(program)?);
|
return Ok(v.inner().get_size(program)?);
|
||||||
}
|
}
|
||||||
if let Some(v) = program.types.get(&name) {
|
if let Some(v) = program.types.get(&name) {
|
||||||
|
match v {
|
||||||
|
TypeType::Normal(v) => {
|
||||||
return Ok(v.inner().size_of(program)?);
|
return Ok(v.inner().size_of(program)?);
|
||||||
}
|
}
|
||||||
|
TypeType::Builtin { size, .. } => {
|
||||||
|
return Ok(*size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if let Some(_) = program.enums.get(&name) {
|
if let Some(_) = program.enums.get(&name) {
|
||||||
return Ok(4); // TODO: Make enum size changeable
|
return Ok(4); // TODO: Make enum size changeable
|
||||||
}
|
}
|
||||||
|
|
@ -161,10 +93,7 @@ impl Display for Type {
|
||||||
_ => unreachable!()
|
_ => 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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
|
|
||||||
use crate::{common::loc::LocBox, debug, lerror, parser::{typ::parse_type, Punctuation}, tokeniser::Token};
|
use crate::{common::loc::LocBox, debug, error, 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};
|
use super::{ast::{expr::{Block, CallParams, Expr, IfBranchExpr, IfExpr, Path}, literal::Literal, TokenType}, parse_item, utils, Delimiter, Keyword};
|
||||||
|
|
||||||
|
|
@ -317,15 +317,10 @@ fn parse_literal(tokens: &mut Vec<Token>) -> Result<LocBox<Expr>> {
|
||||||
bail!("")
|
bail!("")
|
||||||
};
|
};
|
||||||
let count = parse_expr(tokens, 0, false)?.unwrap();
|
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), "")?;
|
utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::SquareR), "")?;
|
||||||
return Ok(LocBox::new(start.loc(), Expr::Literal(Literal::ArrayRepeat {
|
return Ok(LocBox::new(start.loc(), Expr::Literal(Literal::ArrayRepeat {
|
||||||
val: Box::new(typ),
|
val: Box::new(typ),
|
||||||
count: count.val
|
count: Box::new(count)
|
||||||
})));
|
})));
|
||||||
} else {
|
} else {
|
||||||
if let Some(curr) = tokens.last() {
|
if let Some(curr) = tokens.last() {
|
||||||
|
|
@ -341,7 +336,7 @@ fn parse_literal(tokens: &mut Vec<Token>) -> Result<LocBox<Expr>> {
|
||||||
|
|
||||||
fn parse_struct_literal(tokens: &mut Vec<Token>, name: Path) -> 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 start = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::CurlyL), "")?;
|
||||||
let mut fields = BTreeMap::new();
|
let mut fields = HashMap::new();
|
||||||
while !tokens.is_empty() {
|
while !tokens.is_empty() {
|
||||||
if let Some(_) = utils::check_consume(tokens, TokenType::Delim(Delimiter::CurlyR)) {
|
if let Some(_) = utils::check_consume(tokens, TokenType::Delim(Delimiter::CurlyR)) {
|
||||||
break;
|
break;
|
||||||
|
|
@ -389,8 +384,8 @@ fn parse_path(tokens: &mut Vec<Token>) -> Result<LocBox<Expr>> {
|
||||||
fn parse_unop(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, &[
|
let typ = utils::check_consume_or_err_from_many(tokens, &[
|
||||||
TokenType::Punct(Punctuation::Not),
|
TokenType::Punct(Punctuation::Not),
|
||||||
TokenType::Punct(Punctuation::Plus), // Make number positive
|
TokenType::Punct(Punctuation::Plus),
|
||||||
TokenType::Punct(Punctuation::Minus), // make number negative
|
TokenType::Punct(Punctuation::Minus),
|
||||||
TokenType::Punct(Punctuation::Ampersand),
|
TokenType::Punct(Punctuation::Ampersand),
|
||||||
TokenType::Punct(Punctuation::Star),
|
TokenType::Punct(Punctuation::Star),
|
||||||
], "")?;
|
], "")?;
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,7 @@ pub fn parse_program(mut tokens: Vec<Token>) -> Result<Program> {
|
||||||
types: HashMap::new(),
|
types: HashMap::new(),
|
||||||
structs: HashMap::new(),
|
structs: HashMap::new(),
|
||||||
static_vars: HashMap::new(),
|
static_vars: HashMap::new(),
|
||||||
const_vars: HashMap::new(),
|
const_vars: HashMap::new()
|
||||||
scope: None
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ use anyhow::bail;
|
||||||
use crate::common::loc::LocBox;
|
use crate::common::loc::LocBox;
|
||||||
use crate::lerror;
|
use crate::lerror;
|
||||||
use crate::parser::ast::TokenType;
|
use crate::parser::ast::TokenType;
|
||||||
use crate::parser::ast::statement::Let;
|
|
||||||
use crate::parser::expr::parse_expr;
|
use crate::parser::expr::parse_expr;
|
||||||
use crate::parser::{Delimiter, Ident, Keyword, Punctuation};
|
use crate::parser::{Delimiter, Ident, Keyword, Punctuation};
|
||||||
use crate::tokeniser::Token;
|
use crate::tokeniser::Token;
|
||||||
|
|
@ -122,7 +121,7 @@ fn parse_let(tokens: &mut Vec<Token>) -> Result<LocBox<Statement>> {
|
||||||
val = Some(_val);
|
val = Some(_val);
|
||||||
}
|
}
|
||||||
_ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), "")?;
|
_ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), "")?;
|
||||||
Ok(LocBox::new(kw.loc(), Statement::Let(Let{ name, typ, val })))
|
Ok(LocBox::new(kw.loc(), Statement::Let { name, typ, val }))
|
||||||
}
|
}
|
||||||
fn parse_constant(tokens: &mut Vec<Token>) -> Result<LocBox<Statement>> {
|
fn parse_constant(tokens: &mut Vec<Token>) -> Result<LocBox<Statement>> {
|
||||||
let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Const), "")?;
|
let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Const), "")?;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use anyhow::{Result, bail};
|
use anyhow::Result;
|
||||||
|
|
||||||
use crate::{common::loc::LocBox, lerror, parser::{Delimiter, ast::{expr::Expr, literal::Literal}}, tokeniser::Token};
|
use crate::{common::loc::LocBox, error, logger::log, parser::Delimiter, tokeniser::Token};
|
||||||
|
|
||||||
use super::{ast::{typ::Type, TokenType}, expr::parse_expr, utils, Keyword, Punctuation};
|
use super::{ast::{typ::Type, TokenType}, expr::parse_expr, utils, Keyword, Punctuation};
|
||||||
|
|
||||||
|
|
@ -26,18 +26,9 @@ pub fn parse_type(tokens: &mut Vec<Token>) -> Result<LocBox<Type>> {
|
||||||
let itm_typ = parse_type(tokens)?;
|
let itm_typ = parse_type(tokens)?;
|
||||||
if let Some(_) = utils::check_consume(tokens, TokenType::Punct(Punctuation::Semi)) {
|
if let Some(_) = utils::check_consume(tokens, TokenType::Punct(Punctuation::Semi)) {
|
||||||
let count = parse_expr(tokens, 0, false)?.unwrap();
|
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 {
|
typ = Type::SizedArray {
|
||||||
inner: Box::new(itm_typ.inner().clone()),
|
inner: Box::new(itm_typ.inner().clone()),
|
||||||
count: count
|
count
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
typ = Type::UnsizedArray {
|
typ = Type::UnsizedArray {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use std::{fs::File, path::{Path, PathBuf}};
|
||||||
use crate::{cli::CliArgs, parser::ast::Program};
|
use crate::{cli::CliArgs, parser::ast::Program};
|
||||||
|
|
||||||
mod x86_64;
|
mod x86_64;
|
||||||
//mod none;
|
mod none;
|
||||||
|
|
||||||
pub fn get_default_target() -> String {
|
pub fn get_default_target() -> String {
|
||||||
x86_64::cgen::linux::CGen::get_target_triple().to_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::asmgen::linux::AsmGen::get_target_triple(),
|
||||||
// x86_64::cgen::linux::CGen::get_target_triple(),
|
// x86_64::cgen::linux::CGen::get_target_triple(),
|
||||||
// x86_64::llvmgen::linux::LlvmGen::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(),
|
x86_64::cgen::linux::CGen::get_target_triple(),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{fs::File, ops::Deref};
|
use std::{fs::File, ops::Deref};
|
||||||
use std::io::Write;
|
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};
|
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};
|
||||||
|
|
||||||
const INTERNAL_CODE: &'static str = include_str!("internals.c");
|
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<()> {
|
fn write_code(&mut self, program: &crate::parser::ast::Program, f: &mut File) -> anyhow::Result<()> {
|
||||||
self.write_fat_comment(f, "Internal number types");
|
self.write_fat_comment(f, "Internal number types");
|
||||||
for (name, typ) in &program.types {
|
for (name, typ) in &program.types {
|
||||||
if let Type::Builtin { name: _, size: _, signed: _ } = typ.inner() {
|
if let TypeType::Builtin { size: _, signed: _ } = typ {
|
||||||
self.write_internal_type(f, program, name, typ.inner())?;
|
self.write_internal_type(f, program, name, typ)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -34,7 +34,9 @@ impl Target for CGen {
|
||||||
|
|
||||||
self.write_fat_comment(f, "Type aliases");
|
self.write_fat_comment(f, "Type aliases");
|
||||||
for (name, typ) in &program.types {
|
for (name, typ) in &program.types {
|
||||||
self.write_typedef(f, program, typ.inner(), name)?;
|
if let TypeType::Normal(t) = typ {
|
||||||
|
self.write_typedef(f, program, t.inner(), name)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.write_fat_comment(f, "Struct definitions");
|
self.write_fat_comment(f, "Struct definitions");
|
||||||
|
|
@ -43,7 +45,7 @@ impl Target for CGen {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.write_fat_comment(f, "Function forward declarations");
|
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())?;
|
writeln!(f, "// {}", func.get_def_as_str())?;
|
||||||
if let Some(rett) = &func.ret_type {
|
if let Some(rett) = &func.ret_type {
|
||||||
slf.write_type(f, program, rett.inner())?;
|
slf.write_type(f, program, rett.inner())?;
|
||||||
|
|
@ -119,7 +121,7 @@ impl CGen {
|
||||||
Expr::If(_ifexpr) => {
|
Expr::If(_ifexpr) => {
|
||||||
|
|
||||||
}
|
}
|
||||||
Expr::BinOp { typ, .. } => {
|
Expr::BinOp { typ, left, right } => {
|
||||||
match typ {
|
match typ {
|
||||||
Punctuation::Eq => {
|
Punctuation::Eq => {
|
||||||
|
|
||||||
|
|
@ -180,7 +182,6 @@ impl CGen {
|
||||||
pf.push_str(&part(f, program, inner)?);
|
pf.push_str(&part(f, program, inner)?);
|
||||||
pf.push_str("[]");
|
pf.push_str("[]");
|
||||||
}
|
}
|
||||||
Type::Builtin { .. } => ()
|
|
||||||
}
|
}
|
||||||
Ok(pf)
|
Ok(pf)
|
||||||
}
|
}
|
||||||
|
|
@ -222,14 +223,14 @@ impl CGen {
|
||||||
write!(f, "[]")?;
|
write!(f, "[]")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Type::Builtin { .. } => ()
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_internal_type(&mut self, f: &mut File, _program: &Program, _name: &Ident, typ: &Type) -> anyhow::Result<()> {
|
fn write_internal_type(&mut self, f: &mut File, program: &Program, name: &Ident, typ: &TypeType) -> anyhow::Result<()> {
|
||||||
match typ {
|
match typ {
|
||||||
Type::Builtin{ name, size, signed } => {
|
TypeType::Normal(typ) => unreachable!(),
|
||||||
|
TypeType::Builtin{ size, signed } => {
|
||||||
if *size == 0 {
|
if *size == 0 {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
@ -248,7 +249,7 @@ impl CGen {
|
||||||
8 => write!(f, "long long ")?,
|
8 => write!(f, "long long ")?,
|
||||||
3 | 5 | 6 | 7 => unreachable!(),
|
3 | 5 | 6 | 7 => unreachable!(),
|
||||||
}
|
}
|
||||||
writeln!(f, "{};", name)?;
|
writeln!(f, "{};", name.0)?;
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
@ -266,7 +267,7 @@ impl CGen {
|
||||||
Ok(())
|
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())?;
|
writeln!(f, "\n\n// {}", func.get_def_as_str())?;
|
||||||
if let Some(rett) = &func.ret_type {
|
if let Some(rett) = &func.ret_type {
|
||||||
self.write_type(f, program, rett.inner())?;
|
self.write_type(f, program, rett.inner())?;
|
||||||
|
|
@ -294,7 +295,7 @@ impl CGen {
|
||||||
Ast::Expr(expr) => {
|
Ast::Expr(expr) => {
|
||||||
self.write_expr(f, program, expr.inner(), expr.loc())?
|
self.write_expr(f, program, expr.inner(), expr.loc())?
|
||||||
}
|
}
|
||||||
Ast::Statement(_) => {
|
Ast::Statement(stat) => {
|
||||||
//todo!()
|
//todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{collections::HashMap, fmt::Display};
|
use std::{collections::HashMap, fmt::Display};
|
||||||
use anyhow::bail;
|
use anyhow::bail;
|
||||||
use parse_int::parse;
|
use parse_int::parse;
|
||||||
use crate::{common::{loc::LocIncr, Loc},lerror};
|
use crate::{common::{loc::LocIncr, Loc}, error, lerror};
|
||||||
|
|
||||||
pub mod tokentype;
|
pub mod tokentype;
|
||||||
use tokentype::*;
|
use tokentype::*;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
use core::panic;
|
use core::panic;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
use crate::parser::ast::expr::Path;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct Ident(pub String);
|
pub struct Ident(pub String);
|
||||||
|
|
||||||
|
|
@ -12,12 +10,6 @@ impl Display for Ident {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ident {
|
|
||||||
pub fn as_path(self) -> Path {
|
|
||||||
Path(vec![self])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct Number {
|
pub struct Number {
|
||||||
|
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
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(())
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use anyhow::bail;
|
use anyhow::{anyhow, bail};
|
||||||
|
|
||||||
use crate::{common::{Loc, loc::LocBox}, parser::ast::{Ast, Program, Punctuation, TokenType, expr::*, statement::*, typ::Type}};
|
use crate::{common::{loc::LocBox, Loc}, parser::ast::{expr::{Block, Expr}, statement::{Statement, TypeAlias}, typ::Type, Ast, Program}};
|
||||||
|
|
||||||
pub mod predefined;
|
pub mod predefined;
|
||||||
pub mod calculate_types;
|
|
||||||
|
struct Scope {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
pub fn validate_code(prog: &mut Program) -> anyhow::Result<()> {
|
pub fn validate_code(prog: &mut Program) -> anyhow::Result<()> {
|
||||||
let Block(items) = prog.ast.clone();
|
let Block(items) = prog.ast.clone();
|
||||||
|
|
@ -17,9 +20,24 @@ pub fn validate_code(prog: &mut Program) -> anyhow::Result<()> {
|
||||||
//dbg!(&prog.enums);
|
//dbg!(&prog.enums);
|
||||||
//dbg!(&prog.member_functions);
|
//dbg!(&prog.member_functions);
|
||||||
//dbg!(&prog.functions);
|
//dbg!(&prog.functions);
|
||||||
for item in items.iter() {
|
for item in items {
|
||||||
match item {
|
match item {
|
||||||
Ast::Statement(stat) => validate_stat(prog, &stat, CurrentState::Outside)?,
|
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::Expr(_) => unreachable!()
|
Ast::Expr(_) => unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -28,410 +46,6 @@ pub fn validate_code(prog: &mut Program) -> anyhow::Result<()> {
|
||||||
Ok(())
|
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) = <.val && let Some(t) = <.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, ¶m.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<()> {
|
fn check_that_types_exist_for_items(prog: &mut Program, items: &Vec<Ast>) -> anyhow::Result<()> {
|
||||||
let mut errored = false;
|
let mut errored = false;
|
||||||
for item in items {
|
for item in items {
|
||||||
|
|
@ -502,11 +116,10 @@ fn validate_type(prog: &mut Program, typ: &LocBox<Type>) -> anyhow::Result<()> {
|
||||||
prog.structs.get(typ).is_some() {
|
prog.structs.get(typ).is_some() {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
lerror!(loc, "Could not find type '{}'", typ.0);
|
// lerror!(loc, "Could not find type '{}'", typ.0);
|
||||||
bail!("")
|
bail!("")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Type::Builtin { .. } => Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f(prog, typ.inner(), typ.loc())
|
f(prog, typ.inner(), typ.loc())
|
||||||
|
|
@ -540,7 +153,7 @@ fn collect_types_and_constants(prog: &mut Program, items: &Vec<Ast>) {
|
||||||
}
|
}
|
||||||
Statement::TypeAlias(alias) => {
|
Statement::TypeAlias(alias) => {
|
||||||
let typ = alias.clone().typ.inner().clone();
|
let typ = alias.clone().typ.inner().clone();
|
||||||
prog.types.insert(alias.name.clone(), LocBox::new(stat.loc(), typ));
|
prog.types.insert(alias.name.clone(), predefined::TypeType::Normal(LocBox::new(stat.loc(), typ)));
|
||||||
}
|
}
|
||||||
Statement::Let { .. } => (),
|
Statement::Let { .. } => (),
|
||||||
Statement::ConstVar(var) => {
|
Statement::ConstVar(var) => {
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use crate::common::Loc;
|
use crate::common::Loc;
|
||||||
use crate::parser::ast::expr::Path;
|
|
||||||
use crate::parser::typ::parse_type;
|
use crate::parser::typ::parse_type;
|
||||||
use crate::{common::loc::LocBox, parser::ast::{statement::Function, typ::Type, Ident, Program}};
|
use crate::{common::loc::LocBox, parser::ast::{statement::Function, typ::Type, Ident, Program}};
|
||||||
|
|
||||||
#[cfg(target_arch="x86_64")]
|
#[cfg(target_arch="x86_64")]
|
||||||
pub const SIZE: usize = 8;
|
const SIZE: usize = 8;
|
||||||
#[cfg(target_arch="x86")]
|
#[cfg(target_arch="x86")]
|
||||||
pub const SIZE: usize = 4;
|
const SIZE: usize = 4;
|
||||||
|
|
||||||
lazy_static!(
|
lazy_static!(
|
||||||
pub static ref TYPES_RAW: HashMap<&'static str, (usize, bool)> = [
|
pub static ref TYPES_RAW: HashMap<&'static str, (usize, bool)> = [
|
||||||
|
|
@ -23,7 +22,6 @@ lazy_static!(
|
||||||
("i16", (2, true)),
|
("i16", (2, true)),
|
||||||
("i32", (4, true)),
|
("i32", (4, true)),
|
||||||
("i64", (8, true)),
|
("i64", (8, true)),
|
||||||
("bool", (1, true)),
|
|
||||||
].into();
|
].into();
|
||||||
pub static ref FUNCTIONS: HashMap<&'static str, (Vec<(&'static str, &'static str)>, &'static str)> = [
|
pub static ref FUNCTIONS: HashMap<&'static str, (Vec<(&'static str, &'static str)>, &'static str)> = [
|
||||||
("syscall", (vec![
|
("syscall", (vec![
|
||||||
|
|
@ -34,14 +32,18 @@ lazy_static!(
|
||||||
].into();
|
].into();
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum TypeType {
|
||||||
|
Normal(LocBox<Type>),
|
||||||
|
Builtin {
|
||||||
|
size: usize,
|
||||||
|
signed: bool,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn load_builtin(prog: &mut Program) {
|
pub fn load_builtin(prog: &mut Program) {
|
||||||
let loc = Loc::new("(internal)", 0, 0);
|
|
||||||
for (name, (size, signed)) in TYPES_RAW.iter() {
|
for (name, (size, signed)) in TYPES_RAW.iter() {
|
||||||
prog.types.insert(
|
prog.types.insert(Ident(name.to_string()), TypeType::Builtin{ size: *size, signed: *signed });
|
||||||
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() {
|
for (name, (args, ret_typ)) in FUNCTIONS.iter() {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user