no segfault!
This commit is contained in:
parent
1f4645ed24
commit
834b5b1213
|
|
@ -1,6 +1,6 @@
|
|||
use std::fmt::{Debug, Display};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
|
||||
pub struct Loc {
|
||||
file: String,
|
||||
line: usize,
|
||||
|
|
@ -27,7 +27,7 @@ impl Loc {
|
|||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct LocBox<T: Clone + Debug> {
|
||||
inner: T,
|
||||
loc: Loc
|
||||
|
|
|
|||
|
|
@ -25,9 +25,8 @@ 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.literals);
|
||||
progs.push((fp, prog));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use crate::{common::loc::LocBox, parser::ast::{Program, literal::Literal}, token
|
|||
|
||||
use super::{typ::Type, Ast};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Hash)]
|
||||
pub enum Expr {
|
||||
// Comment(Comment),
|
||||
Group(Box<LocBox<Expr>>),
|
||||
|
|
@ -16,8 +16,9 @@ pub enum Expr {
|
|||
typ: Punctuation,
|
||||
left: Box<LocBox<Expr>>,
|
||||
right: Box<LocBox<Expr>>,
|
||||
signed: bool,
|
||||
},
|
||||
Literal(super::literal::Literal),
|
||||
Literal(String, super::literal::Literal), // string is id
|
||||
ArrayIndex {
|
||||
name: Box<LocBox<Expr>>,
|
||||
index: Box<LocBox<Expr>>,
|
||||
|
|
@ -27,20 +28,21 @@ pub enum Expr {
|
|||
path: Box<LocBox<Expr>>,
|
||||
params: CallParams, // LocBox<Expr> ~ (, Expr)*
|
||||
},
|
||||
//MethodCall {
|
||||
// var_name: Box<LocBox<Expr>>,
|
||||
// method_name: Ident,
|
||||
// params: CallParams,
|
||||
//},
|
||||
MethodCall {
|
||||
left: Box<LocBox<Expr>>,
|
||||
params: CallParams,
|
||||
},
|
||||
|
||||
/// the left side only exists on the /.|->/ chain
|
||||
FieldAccess {
|
||||
left: Box<Option<LocBox<Expr>>>,
|
||||
right: Box<LocBox<Expr>>,
|
||||
offset: usize
|
||||
},
|
||||
PtrFieldAccess {
|
||||
left: Box<Option<LocBox<Expr>>>,
|
||||
right: Box<LocBox<Expr>>,
|
||||
offset: usize
|
||||
},
|
||||
ForLoop {
|
||||
init: Box<Ast>,
|
||||
|
|
@ -56,10 +58,7 @@ pub enum Expr {
|
|||
body: Block,
|
||||
},
|
||||
If(IfExpr),
|
||||
Struct {
|
||||
path: Path,
|
||||
fields: BTreeMap<Ident, LocBox<Expr>>,
|
||||
},
|
||||
Struct(String, StructLit),
|
||||
Return(Box<Option<LocBox<Expr>>>),
|
||||
Break,
|
||||
Continue,
|
||||
|
|
@ -69,6 +68,12 @@ pub enum Expr {
|
|||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Hash, PartialEq, PartialOrd)]
|
||||
pub struct StructLit {
|
||||
pub path: Path,
|
||||
pub fields: BTreeMap<Ident, LocBox<Expr>>,
|
||||
}
|
||||
|
||||
impl Expr {
|
||||
pub fn unwrap_path(&self) -> Path {
|
||||
let Expr::Path(p) = self else {panic!("Unwrapping")};
|
||||
|
|
@ -76,7 +81,7 @@ impl Expr {
|
|||
}
|
||||
pub fn as_number(&self, prog: &Program) -> Option<Number> {
|
||||
match self {
|
||||
Self::Literal(Literal::Number(num)) => Some(*num),
|
||||
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)
|
||||
|
|
@ -91,10 +96,10 @@ impl Expr {
|
|||
|
||||
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Hash)]
|
||||
pub struct CallParams(pub Vec<LocBox<Expr>>);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Hash)]
|
||||
pub struct Block(pub Vec<Ast>);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Hash)]
|
||||
|
|
@ -113,14 +118,20 @@ impl Display for Path {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
impl Path {
|
||||
pub fn display_asm_compat(&self) -> String {
|
||||
self.to_string().replace("::", "$")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Hash)]
|
||||
pub struct IfExpr {
|
||||
pub test: Box<LocBox<Expr>>,
|
||||
pub body: Block,
|
||||
pub else_if: Option<IfBranchExpr>
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Hash)]
|
||||
pub enum IfBranchExpr {
|
||||
ElseIf(Box<IfExpr>),
|
||||
Else(Block)
|
||||
|
|
|
|||
|
|
@ -3,13 +3,14 @@ use crate::{common::{Loc, loc::LocBox}, parser::ast::{Program, typ::Type}, token
|
|||
|
||||
use super::expr::Expr;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Hash)]
|
||||
pub enum Literal {
|
||||
Number(Number),
|
||||
Ident(Ident),
|
||||
String(TString),
|
||||
Char(Char),
|
||||
Array(Vec<LocBox<Expr>>),
|
||||
Bool(bool),
|
||||
ArrayRepeat {
|
||||
val: Box<LocBox<Expr>>,
|
||||
count: usize,
|
||||
|
|
@ -19,26 +20,31 @@ pub enum Literal {
|
|||
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::Number(_) => Type::Builtin { name: String::from("usize"), size: SIZE as u8, signed: false },
|
||||
Self::Ident(ident) => Type::Owned(ident.clone()),
|
||||
Self::String(_) => Type::Owned(Ident(String::from("str"))),
|
||||
Self::String(_) => Type::Ref { inner: Box::new(Type::Owned(Ident(String::from("str")))), mutable: false},
|
||||
Self::Char(_) => Type::Owned(Ident(String::from("char"))),
|
||||
Self::Bool(_) => Type::Owned(Ident(String::from("bool"))),
|
||||
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 })))
|
||||
count: LocBox::new(&Loc::default(), Expr::Literal(String::new(), Literal::Number(Number { val: 0, base: 10, signed: false })))
|
||||
}
|
||||
} else {
|
||||
let item = arr.first().unwrap();
|
||||
let loc = item.loc().clone();
|
||||
let mut item = item.inner().clone();
|
||||
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 })))
|
||||
inner: Box::new(validate_expr(prog, &mut item)?.unwrap()),
|
||||
count: LocBox::new(&loc, Expr::Literal(String::new(), 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 })))}
|
||||
let loc = val.loc().clone();
|
||||
let mut val = val.inner().clone();
|
||||
Type::SizedArray { inner: Box::new(validate_expr(prog, &mut val)?.unwrap()), count: LocBox::new(&loc, Expr::Literal(String::new(), Literal::Number(Number { val: *count, base: 10, signed: false })))}
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::collections::HashMap;
|
|||
|
||||
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, parser::ast::{expr::StructLit, literal::Literal, statement::Let, typ::Type}};
|
||||
pub use crate::tokeniser::tokentype::*;
|
||||
|
||||
pub mod expr;
|
||||
|
|
@ -11,7 +11,7 @@ pub mod statement;
|
|||
pub mod typ;
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Scope {
|
||||
pub vars: HashMap<Ident, LocBox<Let>>,
|
||||
pub static_vars: HashMap<Ident, StaticVar>,
|
||||
|
|
@ -29,7 +29,10 @@ pub struct Program {
|
|||
pub member_functions: HashMap<Ident, HashMap<Ident, LocBox<Function>>>,
|
||||
pub static_vars: HashMap<Ident, StaticVar>,
|
||||
pub const_vars: HashMap<Ident, ConstVar>,
|
||||
pub scope: Option<Scope>
|
||||
pub literals: HashMap<String, Literal>, // string is id of literal
|
||||
pub struct_literals: HashMap<String, StructLit>, // string is id of literal
|
||||
pub scope: Option<Scope>,
|
||||
pub curr_fn_args: HashMap<Ident, LocBox<Type>>
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -102,7 +105,7 @@ impl Program {
|
|||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Hash)]
|
||||
pub enum Ast {
|
||||
Expr(LocBox<expr::Expr>),
|
||||
Statement(LocBox<statement::Statement>),
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::bail;
|
||||
|
||||
use crate::{common::loc::LocBox, lerror, parser::ast::expr::Path};
|
||||
use crate::{common::loc::LocBox, lerror};
|
||||
|
||||
use super::{expr::{Block, Expr}, literal::Literal, typ::Type, Char, Ident, Number, Program, TString};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Hash)]
|
||||
pub enum Statement {
|
||||
Fn(Function),
|
||||
TypeAlias(TypeAlias),
|
||||
|
|
@ -18,45 +20,45 @@ pub enum Statement {
|
|||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Hash)]
|
||||
pub struct Let {
|
||||
pub name: Ident,
|
||||
pub typ: Option<LocBox<Type>>,
|
||||
pub val: Option<LocBox<Expr>>,
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Hash)]
|
||||
pub struct ConstVar {
|
||||
pub name: Ident,
|
||||
pub typ: LocBox<Type>,
|
||||
pub val: LocBox<Expr>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Hash)]
|
||||
pub struct StaticVar {
|
||||
pub name: Ident,
|
||||
pub typ: LocBox<Type>,
|
||||
pub val: LocBox<Expr>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Hash)]
|
||||
pub struct TypeAlias {
|
||||
pub name: Ident,
|
||||
pub typ: LocBox<Type>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Hash)]
|
||||
pub struct Struct {
|
||||
pub name: Ident,
|
||||
pub fields: Vec<(Ident, LocBox<Type>)>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Hash)]
|
||||
pub struct Enum {
|
||||
pub name: Ident,
|
||||
pub fields: Vec<Ident>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Hash)]
|
||||
pub struct Function {
|
||||
pub struct_name: Option<Ident>,
|
||||
pub name: Ident,
|
||||
|
|
@ -125,49 +127,51 @@ impl Struct {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Hash)]
|
||||
pub enum ConstDataTyp {
|
||||
Byte(u8),
|
||||
Bytes(Vec<u8>),
|
||||
AddrOfConst(Ident),
|
||||
AddrOfStatic(Ident),
|
||||
AddrOfFunc(Ident),
|
||||
Variable(Ident, usize),
|
||||
Array(Vec<ConstDataTyp>)
|
||||
}
|
||||
|
||||
pub fn get_constant_data_as_bytes(program: &Program, value: LocBox<Expr>, is_little_endian: bool, must_be_number: bool) -> anyhow::Result<Vec<ConstDataTyp>> {
|
||||
pub fn get_constant_data_as_bytes(program: &Program, struct_items: &HashMap<Ident, usize>, value: LocBox<Expr>, is_big_endian: bool, must_be_number: bool) -> anyhow::Result<ConstDataTyp> {
|
||||
match value.inner() {
|
||||
Expr::Literal(lit) => {
|
||||
Expr::Literal(_, lit) => {
|
||||
match lit {
|
||||
Literal::Char(Char(c)) => {
|
||||
if must_be_number {
|
||||
lerror!(value.loc(), "Expected number got char");
|
||||
bail!("")
|
||||
}
|
||||
Ok(vec![ConstDataTyp::Byte(*c as u8)])
|
||||
Ok(ConstDataTyp::Bytes(vec![*c as u8]))
|
||||
},
|
||||
Literal::String(TString { val, cstr }) => {
|
||||
if must_be_number {
|
||||
lerror!(value.loc(), "Expected number got string");
|
||||
bail!("")
|
||||
}
|
||||
let mut val = val.chars().into_iter().map(|f| ConstDataTyp::Byte(f as u8)).collect::<Vec<_>>();
|
||||
let mut val = val.chars().into_iter().map(|v| v as u8).collect::<Vec<u8>>();
|
||||
if *cstr {
|
||||
val.push(ConstDataTyp::Byte(0));
|
||||
val.push(0);
|
||||
}
|
||||
Ok(val)
|
||||
Ok(ConstDataTyp::Bytes(val))
|
||||
}
|
||||
Literal::Number(Number { val, base: _, signed: _ }) => {
|
||||
let mut buf = Vec::new();
|
||||
let mut inc = 0;
|
||||
while inc < 8 {
|
||||
buf.push(ConstDataTyp::Byte(((val << 8*inc) & 0xff) as u8));
|
||||
buf.push(((val << 8*inc) & 0xff) as u8);
|
||||
inc += 1;
|
||||
}
|
||||
|
||||
if is_little_endian {
|
||||
if is_big_endian {
|
||||
buf.reverse();
|
||||
}
|
||||
|
||||
Ok(buf)
|
||||
Ok(ConstDataTyp::Bytes(buf))
|
||||
}
|
||||
Literal::Array(arr) => {
|
||||
if must_be_number {
|
||||
|
|
@ -176,84 +180,89 @@ pub fn get_constant_data_as_bytes(program: &Program, value: LocBox<Expr>, is_lit
|
|||
}
|
||||
let mut bytes = Vec::new();
|
||||
if arr.len() < 1 {
|
||||
return Ok(vec![]);
|
||||
return Ok(ConstDataTyp::Bytes(vec![]));
|
||||
}
|
||||
for item in arr {
|
||||
let mut data = get_constant_data_as_bytes(program, item.clone(), is_little_endian, must_be_number)?;
|
||||
bytes.append(&mut data);
|
||||
let data = get_constant_data_as_bytes(program, struct_items, item.clone(), is_big_endian, must_be_number)?;
|
||||
bytes.push(data);
|
||||
}
|
||||
|
||||
Ok(bytes)
|
||||
Ok(ConstDataTyp::Array(bytes))
|
||||
}
|
||||
Literal::ArrayRepeat { val, count } => {
|
||||
if must_be_number {
|
||||
lerror!(value.loc(), "Expected number got repeating array");
|
||||
bail!("")
|
||||
}
|
||||
let mut val = get_constant_data_as_bytes(program, (**val).clone(), is_little_endian, must_be_number)?;
|
||||
|
||||
let val = get_constant_data_as_bytes(program, struct_items, (**val).clone(), is_big_endian, must_be_number)?;
|
||||
|
||||
let mut num = Vec::new();
|
||||
let mut inc = 0;
|
||||
while inc < 8 {
|
||||
num.push(ConstDataTyp::Byte(((count << 8*inc) & 0xff) as u8));
|
||||
num.push(((count << 8*inc) & 0xff) as u8);
|
||||
inc += 1;
|
||||
}
|
||||
|
||||
if is_little_endian {
|
||||
if is_big_endian {
|
||||
num.reverse();
|
||||
}
|
||||
|
||||
let mut count = 0 as usize;
|
||||
for b in num {
|
||||
let ConstDataTyp::Byte(b) = b else {unreachable!()};
|
||||
count = b as usize;
|
||||
count <<= 8;
|
||||
}
|
||||
let orig = val.clone();
|
||||
let mut arr = Vec::new();
|
||||
for _ in 0..count {
|
||||
val.append(&mut orig.clone());
|
||||
arr.push(orig.clone());
|
||||
}
|
||||
Ok(val)
|
||||
Ok(ConstDataTyp::Array(arr))
|
||||
}
|
||||
Literal::Ident(name) => {
|
||||
if let Some(var) = program.const_vars.get(name) {
|
||||
Ok(get_constant_data_as_bytes(program, var.val.clone(), is_little_endian, must_be_number)?)
|
||||
} else if let Some(_) = program.static_vars.get(name) {
|
||||
lerror!(value.loc(), "Statics cannot be passed by value, use a reference");
|
||||
bail!("")
|
||||
} else if let Some(_) = program.functions.get(name) {
|
||||
Ok(vec![ConstDataTyp::AddrOfFunc(name.clone())])
|
||||
} else {
|
||||
lerror!(value.loc(), "Unable to find ident '{name}'");
|
||||
bail!("")
|
||||
}
|
||||
Literal::Bool(v) => {
|
||||
Ok(ConstDataTyp::Bytes(vec![*v as u8]))
|
||||
}
|
||||
//Literal::Struct { name, fields } => {
|
||||
// if must_be_number {
|
||||
// lerror!(value.loc(), "Expected number got struct literal");
|
||||
// bail!("")
|
||||
// }
|
||||
// let Some(strct) = program.structs.get(name) else {
|
||||
// lerror!(value.loc(), "Could not find struct {name}");
|
||||
// bail!("")
|
||||
// };
|
||||
//
|
||||
// let mut strct_fields = HashMap::new();
|
||||
// for (name, typ) in &strct.inner().fields {
|
||||
// strct_fields.insert(name, typ);
|
||||
// }
|
||||
//
|
||||
// for (name, val) in fields {
|
||||
// if let Some(_fld) = strct_fields.get(name) {
|
||||
// // TODO: Actually check if the fields are the right type
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// todo!()
|
||||
//}
|
||||
|
||||
Literal::Ident(_) => unreachable!()
|
||||
}
|
||||
|
||||
}
|
||||
_ => unreachable!()
|
||||
Expr::Struct(_, strct) => {
|
||||
let mut bytes = Vec::new();
|
||||
if must_be_number {
|
||||
lerror!(value.loc(), "Expected number got struct literal");
|
||||
bail!("")
|
||||
}
|
||||
|
||||
let mut items = HashMap::new();
|
||||
|
||||
for (name, item) in program.structs.get(&strct.path.0.first().unwrap()).unwrap().inner().fields.iter() {
|
||||
items.insert(name.clone(), item.inner().size_of(program)?);
|
||||
}
|
||||
|
||||
for field in &strct.fields {
|
||||
bytes.push(get_constant_data_as_bytes(program, &items, field.1.clone(), is_big_endian, must_be_number)?);
|
||||
}
|
||||
|
||||
Ok(ConstDataTyp::Array(bytes))
|
||||
}
|
||||
Expr::Path(path) => {
|
||||
let name = path.0.last().unwrap();
|
||||
if let Some(var) = program.const_vars.get(name) {
|
||||
Ok(get_constant_data_as_bytes(program, struct_items, var.val.clone(), is_big_endian, must_be_number)?)
|
||||
} else if let Some(_) = program.static_vars.get(name) {
|
||||
lerror!(value.loc(), "Statics cannot be passed by value, use a reference");
|
||||
bail!("")
|
||||
} else if let Some(_) = program.functions.get(name) {
|
||||
Ok(ConstDataTyp::AddrOfFunc(name.clone()))
|
||||
} else if let Some(size) = struct_items.get(name) {
|
||||
Ok(ConstDataTyp::Variable(name.clone(), *size))
|
||||
} else {
|
||||
lerror!(value.loc(), "Unable to find ident '{name}'");
|
||||
bail!("")
|
||||
}
|
||||
|
||||
}
|
||||
v => unreachable!("{v:?}")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ use std::fmt::Display;
|
|||
|
||||
use anyhow::bail;
|
||||
|
||||
use crate::common::loc::LocBox;
|
||||
use crate::{common::loc::LocBox, validator::predefined::get_builtin_from_name};
|
||||
|
||||
use super::{expr::Expr, literal::Literal, Ident, Program};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Hash)]
|
||||
pub enum Type {
|
||||
Ref {
|
||||
inner: Box<Type>,
|
||||
|
|
@ -32,12 +32,44 @@ impl Type {
|
|||
match self {
|
||||
Self::Ref { inner, .. } => inner.get_absolute_value(program),
|
||||
Self::Owned(ident) => {
|
||||
if let Some(t) = get_builtin_from_name(ident.0.as_str()) {
|
||||
return Ok(t)
|
||||
}
|
||||
if let Some(t) = program.curr_fn_args.get(ident) {
|
||||
return Ok(t.inner().clone().get_absolute_value(program)?);
|
||||
} else
|
||||
if program.types.get(ident).is_some() ||
|
||||
program.structs.get(ident).is_some() ||
|
||||
program.enums.get(ident).is_some()
|
||||
{
|
||||
return Ok(self.clone());
|
||||
}
|
||||
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().get_absolute_value(program)?)
|
||||
} else {
|
||||
bail!("owo? missing value: {ident}");
|
||||
}
|
||||
}
|
||||
Self::SizedArray { .. } |
|
||||
Self::Builtin { .. } |
|
||||
Self::UnsizedArray { .. } => Ok(self.clone()),
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_variable_type(&self, program: &Program) -> anyhow::Result<Self> {
|
||||
match self {
|
||||
Self::Owned(ident) => {
|
||||
if let Some(t) = program.types.get(ident) {
|
||||
Ok(t.inner().clone())
|
||||
} else
|
||||
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!("");
|
||||
bail!("owo? missing value: {ident}");
|
||||
}
|
||||
}
|
||||
Self::Ref { .. } |
|
||||
Self::SizedArray { .. } |
|
||||
Self::Builtin { .. } |
|
||||
Self::UnsizedArray { .. } => Ok(self.clone()),
|
||||
|
|
@ -69,6 +101,40 @@ impl Type {
|
|||
}
|
||||
}
|
||||
}
|
||||
// Returns None if non numeric
|
||||
pub fn is_signed(&self, program: &Program) -> Option<bool> {
|
||||
if self.is_ptr(program) {
|
||||
return Some(false);
|
||||
}
|
||||
match self {
|
||||
Self::Ref { inner, .. } => {
|
||||
inner.is_signed(program)
|
||||
}
|
||||
Self::Owned(name) => {
|
||||
match program.types.get(&name) {
|
||||
Some(t) => t.inner().is_signed(program),
|
||||
_ => None
|
||||
}
|
||||
},
|
||||
Self::SizedArray { .. } => None,
|
||||
Self::UnsizedArray { .. } => None,
|
||||
Self::Builtin { name, .. } => {
|
||||
match name.as_str() {
|
||||
"i8" |
|
||||
"i16" |
|
||||
"i32" |
|
||||
"i64" |
|
||||
"isize" => Some(true),
|
||||
"u8" |
|
||||
"u16" |
|
||||
"u32" |
|
||||
"u64" |
|
||||
"usize" => Some(false),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_ptr(&self, program: &Program) -> bool {
|
||||
match self {
|
||||
|
|
@ -96,33 +162,41 @@ impl Type {
|
|||
}
|
||||
}
|
||||
pub fn size_of(&self, program: &Program) -> anyhow::Result<usize> {
|
||||
match self {
|
||||
Self::Ref { .. } => {
|
||||
// TODO: Use the actual ptr size
|
||||
Ok(size_of::<*const ()>())
|
||||
}
|
||||
Self::UnsizedArray { .. } => {
|
||||
bail!("Unsized arrays dont have a known size and must be behind a pointer")
|
||||
}
|
||||
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)?);
|
||||
fn f(t: &Type, program: &Program, behind_a_ptr: bool) -> anyhow::Result<usize> {
|
||||
match t {
|
||||
Type::Ref { .. } => {
|
||||
// TODO: Use the actual ptr size
|
||||
Ok(size_of::<*const ()>())
|
||||
}
|
||||
if let Some(v) = program.types.get(&name) {
|
||||
return Ok(v.inner().size_of(program)?);
|
||||
Type::UnsizedArray { .. } => {
|
||||
if behind_a_ptr {
|
||||
Ok(size_of::<*const ()>())
|
||||
} else {
|
||||
bail!("Unsized arrays dont have a known size and must be behind a pointer");
|
||||
}
|
||||
}
|
||||
if let Some(_) = program.enums.get(&name) {
|
||||
return Ok(4); // TODO: Make enum size changeable
|
||||
Type::SizedArray { inner, .. } => {
|
||||
Ok(inner.size_of(program)? )
|
||||
}
|
||||
Type::Builtin { size, .. } => {
|
||||
Ok(*size as usize)
|
||||
}
|
||||
Type::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) {
|
||||
return Ok(f(v.inner(), program, behind_a_ptr)?);
|
||||
}
|
||||
if let Some(_) = program.enums.get(&name) {
|
||||
return Ok(4); // TODO: Make enum size changeable
|
||||
}
|
||||
bail!("Unknown type '{name}'")
|
||||
}
|
||||
bail!("Unknown type '{name}'")
|
||||
}
|
||||
}
|
||||
|
||||
f(self, program, false)
|
||||
}
|
||||
pub fn size_of_allow_unsized_arrays(&self, program: &Program) -> anyhow::Result<usize> {
|
||||
match self.size_of(program) {
|
||||
|
|
@ -155,7 +229,7 @@ impl Display for Type {
|
|||
Expr::Path(p) => {
|
||||
write!(f, "[{inner}; {p}]")
|
||||
}
|
||||
Expr::Literal(Literal::Number(n)) => {
|
||||
Expr::Literal(_, Literal::Number(n)) => {
|
||||
write!(f, "[{inner}; {n}]")
|
||||
}
|
||||
_ => unreachable!()
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::collections::{BTreeMap, HashMap};
|
|||
|
||||
use anyhow::{bail, Result};
|
||||
|
||||
use crate::{common::loc::LocBox, debug, lerror, parser::{typ::parse_type, Punctuation}, tokeniser::Token};
|
||||
use crate::{common::loc::LocBox, debug, lerror, parser::{Punctuation, ast::expr::StructLit, typ::parse_type}, tokeniser::Token};
|
||||
|
||||
use super::{ast::{expr::{Block, CallParams, Expr, IfBranchExpr, IfExpr, Path}, literal::Literal, TokenType}, parse_item, utils, Delimiter, Keyword};
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ pub fn parse_expr(tokens: &mut Vec<Token>, precedence: usize, consume_semi: bool
|
|||
} else
|
||||
if let Some(_) = utils::check(tokens, TokenType::ident("")) {
|
||||
let p = parse_path(tokens)?;
|
||||
if let Some(_) = utils::check(tokens, TokenType::Delim(Delimiter::CurlyL)) {
|
||||
if let Some(t) = utils::check(tokens, TokenType::Delim(Delimiter::CurlyL)) {
|
||||
Some(parse_struct_literal(tokens, p.inner().unwrap_path())?)
|
||||
} else {
|
||||
Some(p)
|
||||
|
|
@ -63,6 +63,8 @@ pub fn parse_expr(tokens: &mut Vec<Token>, precedence: usize, consume_semi: bool
|
|||
TokenType::number(0, 0, false),
|
||||
TokenType::char('\0'),
|
||||
TokenType::Delim(Delimiter::SquareL),
|
||||
TokenType::Keyword(Keyword::True),
|
||||
TokenType::Keyword(Keyword::False)
|
||||
]) {
|
||||
Some(parse_literal(tokens)?)
|
||||
} else if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::While)) {
|
||||
|
|
@ -74,8 +76,10 @@ pub fn parse_expr(tokens: &mut Vec<Token>, precedence: usize, consume_semi: bool
|
|||
} else if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::Return)) {
|
||||
return Ok(Some(parse_return(tokens)?));
|
||||
} else if let Some(kw) = utils::check_consume(tokens, TokenType::Keyword(Keyword::Break)) {
|
||||
let _ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), "Expected ; at the end of the expression")?;
|
||||
return Ok(Some(LocBox::new(kw.loc(), Expr::Break)));
|
||||
} else if let Some(kw) = utils::check_consume(tokens, TokenType::Keyword(Keyword::Continue)) {
|
||||
let _ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), "Expected ; at the end of the expression")?;
|
||||
return Ok(Some(LocBox::new(kw.loc(), Expr::Continue)));
|
||||
} else if let Some(kw) = utils::check(tokens, TokenType::Keyword(Keyword::If)) {
|
||||
return Ok(Some(LocBox::new(&kw.loc().clone(), Expr::If(parse_if(tokens)?))));
|
||||
|
|
@ -102,7 +106,11 @@ pub fn parse_expr(tokens: &mut Vec<Token>, precedence: usize, consume_semi: bool
|
|||
}
|
||||
|
||||
if let Some(_) = utils::check_from_many(tokens, BINOP_LIST) {
|
||||
return Ok(Some(parse_binop(tokens, res, precedence)?));
|
||||
let v = parse_binop(tokens, res, precedence)?;
|
||||
if consume_semi {
|
||||
_ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), "Expected ; at the end of the expression")?;
|
||||
}
|
||||
return Ok(Some(v));
|
||||
} else {
|
||||
if consume_semi {
|
||||
_ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), "Expected ; at the end of the expression")?;
|
||||
|
|
@ -110,6 +118,9 @@ pub fn parse_expr(tokens: &mut Vec<Token>, precedence: usize, consume_semi: bool
|
|||
return Ok(Some(res));
|
||||
}
|
||||
}
|
||||
if consume_semi {
|
||||
_ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), "Expected ; at the end of the expression")?;
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
|
|
@ -129,10 +140,12 @@ fn parse_cast(tokens: &mut Vec<Token>, left: LocBox<Expr>) -> Result<LocBox<Expr
|
|||
}
|
||||
fn parse_if(tokens: &mut Vec<Token>) -> Result<IfExpr> {
|
||||
let loc = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::If), "")?;
|
||||
let _ = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenL), "")?;
|
||||
let Some(test) = parse_expr(tokens, 0, false)? else {
|
||||
lerror!(loc.loc(), "Expected test for if statement, got nothing");
|
||||
bail!("")
|
||||
};
|
||||
let _ = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenR), "")?;
|
||||
let block = if let Some(_) = utils::check(tokens, TokenType::Delim(Delimiter::CurlyL)) {
|
||||
if let Some(_) = utils::check_2_last(tokens, TokenType::Delim(Delimiter::CurlyR)) {
|
||||
_ = utils::check_consume(tokens, TokenType::Delim(Delimiter::CurlyR));
|
||||
|
|
@ -170,10 +183,12 @@ fn parse_if(tokens: &mut Vec<Token>) -> Result<IfExpr> {
|
|||
}
|
||||
fn parse_while_loop(tokens: &mut Vec<Token>) -> Result<LocBox<Expr>> {
|
||||
let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::While), "")?;
|
||||
let _ = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenL), "")?;
|
||||
let Some(test) = parse_expr(tokens, 0, false)? else {
|
||||
lerror!(kw.loc(), "Expected test comparrison for while loop, got nothing");
|
||||
bail!("")
|
||||
};
|
||||
let _ = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenR), "")?;
|
||||
let block = parse_block(tokens)?;
|
||||
Ok(LocBox::new(kw.loc(), Expr::WhileLoop {
|
||||
test: Box::new(test),
|
||||
|
|
@ -182,6 +197,7 @@ fn parse_while_loop(tokens: &mut Vec<Token>) -> Result<LocBox<Expr>> {
|
|||
}
|
||||
fn parse_for_loop(tokens: &mut Vec<Token>) -> Result<LocBox<Expr>> {
|
||||
let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::For), "")?;
|
||||
let _ = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenL), "")?;
|
||||
let Some(pre) = parse_item(tokens)? else {
|
||||
lerror!(kw.loc(), "Expected init stat for a for loop, got nothing");
|
||||
bail!("")
|
||||
|
|
@ -196,6 +212,7 @@ fn parse_for_loop(tokens: &mut Vec<Token>) -> Result<LocBox<Expr>> {
|
|||
lerror!(kw.loc(), "Expected post expression (usually an index increment) for a for loop, got nothing");
|
||||
bail!("")
|
||||
};
|
||||
let _ = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenR), "")?;
|
||||
let block = parse_block(tokens)?;
|
||||
|
||||
Ok(LocBox::new(kw.loc(), Expr::ForLoop {
|
||||
|
|
@ -211,6 +228,15 @@ fn parse_inf_loop(tokens: &mut Vec<Token>) -> Result<LocBox<Expr>> {
|
|||
Ok(LocBox::new(kw.loc(), Expr::InfLoop { body: block }))
|
||||
}
|
||||
fn parse_fn_call(tokens: &mut Vec<Token>, left: LocBox<Expr>) -> Result<LocBox<Expr>> {
|
||||
match left.inner() {
|
||||
Expr::FieldAccess { .. } |
|
||||
Expr::PtrFieldAccess { .. } => {
|
||||
return parse_member_function_call(tokens, left);
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
|
||||
|
||||
let start = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenL), "")?;
|
||||
let mut params = Vec::new();
|
||||
|
||||
|
|
@ -257,7 +283,33 @@ fn parse_field_access(tokens: &mut Vec<Token>, left: LocBox<Expr>) -> Result<Loc
|
|||
};
|
||||
Ok(LocBox::new(start.loc(), Expr::FieldAccess {
|
||||
left: Box::new(Some(left)),
|
||||
right: Box::new(right)
|
||||
right: Box::new(right),
|
||||
offset: 0
|
||||
}))
|
||||
}
|
||||
|
||||
fn parse_member_function_call(tokens: &mut Vec<Token>, left: LocBox<Expr>) -> Result<LocBox<Expr>> {
|
||||
let start = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenL), "unreachable")?;
|
||||
let mut params = Vec::new();
|
||||
|
||||
while !tokens.is_empty() {
|
||||
if let Some(_) = utils::check(tokens, TokenType::Delim(Delimiter::ParenR)) {
|
||||
break;
|
||||
}
|
||||
let Some(param) = parse_expr(tokens, 0, false)? else {break};
|
||||
params.push(param);
|
||||
if let None = utils::check_consume(tokens, TokenType::Punct(Punctuation::Comma)) {
|
||||
if let None = utils::check(tokens, TokenType::Delim(Delimiter::ParenR)) {
|
||||
lerror!(&utils::get_last_loc(), "Expected ',' or ')' but didnt find either");
|
||||
bail!("")
|
||||
}
|
||||
}
|
||||
}
|
||||
_ = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenR), "");
|
||||
|
||||
Ok(LocBox::new(start.loc(), Expr::MethodCall {
|
||||
left: Box::new(left),
|
||||
params: CallParams(params)
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
@ -274,26 +326,33 @@ fn parse_ptr_field_access(tokens: &mut Vec<Token>, left: LocBox<Expr>) -> Result
|
|||
};
|
||||
Ok(LocBox::new(start.loc(), Expr::PtrFieldAccess {
|
||||
left: Box::new(Some(left)),
|
||||
right: Box::new(right)
|
||||
right: Box::new(right),
|
||||
offset: 0
|
||||
}))
|
||||
}
|
||||
|
||||
fn parse_literal(tokens: &mut Vec<Token>) -> Result<LocBox<Expr>> {
|
||||
if let Some(tkn) = utils::check_consume(tokens, TokenType::Keyword(Keyword::True)) {
|
||||
return Ok(LocBox::new(tkn.loc(), Expr::Literal(String::new(), Literal::Bool(true))));
|
||||
} else
|
||||
if let Some(tkn) = utils::check_consume(tokens, TokenType::Keyword(Keyword::False)) {
|
||||
return Ok(LocBox::new(tkn.loc(), Expr::Literal(String::new(), Literal::Bool(false))));
|
||||
} else
|
||||
if let Some(tkn) = utils::check_consume(tokens, TokenType::string("", false)) {
|
||||
let TokenType::String(str) = tkn.tt() else {unreachable!()};
|
||||
return Ok(LocBox::new(tkn.loc(), Expr::Literal(Literal::String(str.clone()))));
|
||||
return Ok(LocBox::new(tkn.loc(), Expr::Literal(String::new(), Literal::String(str.clone()))));
|
||||
} else
|
||||
if let Some(tkn) = utils::check_consume(tokens, TokenType::number(0, 0, false)) {
|
||||
let TokenType::Number(val) = tkn.tt() else {unreachable!()};
|
||||
return Ok(LocBox::new(tkn.loc(), Expr::Literal(Literal::Number(val.clone()))));
|
||||
return Ok(LocBox::new(tkn.loc(), Expr::Literal(String::new(), Literal::Number(val.clone()))));
|
||||
} else
|
||||
if let Some(tkn) = utils::check_consume(tokens, TokenType::char('\0')) {
|
||||
let TokenType::Char(val) = tkn.tt() else {unreachable!()};
|
||||
return Ok(LocBox::new(tkn.loc(), Expr::Literal(Literal::Char(val.clone()))));
|
||||
return Ok(LocBox::new(tkn.loc(), Expr::Literal(String::new(), Literal::Char(val.clone()))));
|
||||
} else
|
||||
if let Some(start) = utils::check_consume(tokens, TokenType::Delim(Delimiter::SquareL)) {
|
||||
if let Some(_) = utils::check_consume(tokens, TokenType::Delim(Delimiter::SquareR)) {
|
||||
return Ok(LocBox::new(start.loc(), Expr::Literal(Literal::Array(Vec::new()))));
|
||||
return Ok(LocBox::new(start.loc(), Expr::Literal(String::new(), Literal::Array(Vec::new()))));
|
||||
}
|
||||
if *tokens[tokens.len()-2].tt() == TokenType::Punct(Punctuation::Comma) {
|
||||
let first = parse_expr(tokens, 0, false)?;
|
||||
|
|
@ -310,7 +369,7 @@ fn parse_literal(tokens: &mut Vec<Token>) -> Result<LocBox<Expr>> {
|
|||
}
|
||||
}
|
||||
utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::SquareR), "")?;
|
||||
return Ok(LocBox::new(start.loc(), Expr::Literal(Literal::Array(values))));
|
||||
return Ok(LocBox::new(start.loc(), Expr::Literal(String::new(), Literal::Array(values))));
|
||||
} else if *tokens[tokens.len()-2].tt() == TokenType::Punct(Punctuation::Semi) {
|
||||
let Some(typ) = parse_expr(tokens, 0, true)? else {
|
||||
lerror!(start.loc(), "Expected value, found nothing");
|
||||
|
|
@ -318,12 +377,12 @@ fn parse_literal(tokens: &mut Vec<Token>) -> Result<LocBox<Expr>> {
|
|||
};
|
||||
let count = parse_expr(tokens, 0, false)?.unwrap();
|
||||
|
||||
let Expr::Literal(Literal::Number(count)) = count.inner() else {
|
||||
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 {
|
||||
return Ok(LocBox::new(start.loc(), Expr::Literal(String::new(), Literal::ArrayRepeat {
|
||||
val: Box::new(typ),
|
||||
count: count.val
|
||||
})));
|
||||
|
|
@ -348,7 +407,7 @@ fn parse_struct_literal(tokens: &mut Vec<Token>, name: Path) -> Result<LocBox<Ex
|
|||
}
|
||||
|
||||
let name = utils::check_consume_or_err(tokens, TokenType::ident(""), "")?;
|
||||
_ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Colon), "")?;
|
||||
_ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Colon), "wtf?")?;
|
||||
let typ = parse_expr(tokens, 0, false)?.unwrap();
|
||||
fields.insert(name.tt().unwrap_ident(), typ);
|
||||
if let None = utils::check_consume(tokens, TokenType::Punct(Punctuation::Comma)) {
|
||||
|
|
@ -356,7 +415,7 @@ fn parse_struct_literal(tokens: &mut Vec<Token>, name: Path) -> Result<LocBox<Ex
|
|||
break;
|
||||
}
|
||||
}
|
||||
Ok(LocBox::new(start.loc(), Expr::Struct { path: name, fields }))
|
||||
Ok(LocBox::new(start.loc(), Expr::Struct(String::new(), StructLit { path: name, fields })))
|
||||
}
|
||||
|
||||
fn parse_group(tokens: &mut Vec<Token>) -> Result<LocBox<Expr>> {
|
||||
|
|
@ -442,7 +501,8 @@ fn parse_binop(tokens: &mut Vec<Token>, mut lhs: LocBox<Expr>, precedence: usize
|
|||
lhs = LocBox::new(&op_loc, Expr::BinOp {
|
||||
typ: op,
|
||||
left: Box::new(lhs),
|
||||
right: Box::new(rhs)
|
||||
right: Box::new(rhs),
|
||||
signed: false
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,10 @@ pub fn parse_program(mut tokens: Vec<Token>) -> Result<Program> {
|
|||
structs: HashMap::new(),
|
||||
static_vars: HashMap::new(),
|
||||
const_vars: HashMap::new(),
|
||||
scope: None
|
||||
literals: HashMap::new(),
|
||||
struct_literals: HashMap::new(),
|
||||
scope: None,
|
||||
curr_fn_args: HashMap::new()
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ pub fn parse_statement(tokens: &mut Vec<Token>) -> Result<Option<LocBox<Statemen
|
|||
if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::Let)) {
|
||||
Ok(Some(parse_let(tokens)?))
|
||||
} else {
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
|
@ -200,7 +201,7 @@ fn parse_fn_params(tokens: &mut Vec<Token>) -> Result<Vec<(Ident, LocBox<Type>)>
|
|||
break;
|
||||
}
|
||||
let name = utils::check_consume_or_err(tokens, TokenType::ident(""), "")?;
|
||||
utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Colon), "")?;
|
||||
utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Colon), "huhhhhhhhh")?;
|
||||
//dbg!(&name);
|
||||
let typ = parse_type(tokens)?;
|
||||
args.push((name.tt().unwrap_ident(), typ));
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ pub fn parse_type(tokens: &mut Vec<Token>) -> Result<LocBox<Type>> {
|
|||
let count = parse_expr(tokens, 0, false)?.unwrap();
|
||||
|
||||
match count.inner() {
|
||||
Expr::Literal(Literal::Number(_)) |
|
||||
Expr::Literal(_, Literal::Number(_)) |
|
||||
Expr::Path(_) => (),
|
||||
_ => {
|
||||
lerror!(count.loc(), "Only literal numbers are allowed in sized arrays");
|
||||
|
|
|
|||
|
|
@ -1,31 +1,32 @@
|
|||
use std::{fs::File, path::{Path, PathBuf}};
|
||||
use crate::{cli::CliArgs, parser::ast::Program};
|
||||
|
||||
mod x86_64;
|
||||
pub mod x86_64;
|
||||
//mod none;
|
||||
|
||||
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()
|
||||
x86_64::asmgen::linux::AsmGen::get_target_triple().to_string()
|
||||
}
|
||||
|
||||
pub fn get_all_targets() -> Vec<&'static str> {
|
||||
vec![
|
||||
// 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::llvmgen::linux::LlvmGen::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(),
|
||||
]
|
||||
}
|
||||
|
||||
fn get_target_from_triple(triple: &str) -> Box<dyn Target> {
|
||||
match triple {
|
||||
// _ if triple == x86_64::asmgen::linux::AsmGen::get_target_triple() => {
|
||||
// Box::new(x86_64::asmgen::linux::AsmGen::new())
|
||||
// }
|
||||
_ if triple == x86_64::cgen::linux::CGen::get_target_triple() => {
|
||||
Box::new(x86_64::cgen::linux::CGen::new())
|
||||
_ if triple == x86_64::asmgen::linux::AsmGen::get_target_triple() => {
|
||||
Box::new(x86_64::asmgen::linux::AsmGen::new())
|
||||
}
|
||||
// _ if triple == x86_64::cgen::linux::CGen::get_target_triple() => {
|
||||
// Box::new(x86_64::cgen::linux::CGen::new())
|
||||
// }
|
||||
// _ if triple == x86_64::qbegen::linux::QbeGen::get_target_triple() => {
|
||||
// Box::new(x86_64::qbegen::linux::QbeGen::new())
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
use crate::targets::Target;
|
||||
use std::io::Write;
|
||||
use crate::{common::{Loc, loc::LocBox}, parser::ast::{Ast, Ident, Program, Punctuation, expr::{Expr, IfBranchExpr}, literal::Literal, statement::{ConstDataTyp, Function, Statement, get_constant_data_as_bytes}, typ::Type}, targets::Target};
|
||||
use std::{collections::HashMap, fs::File, io::Write};
|
||||
pub struct AsmGen;
|
||||
|
||||
const RUNTIME_CODE: &'static str = include_str!("./runtime.s");
|
||||
|
||||
impl Target for AsmGen {
|
||||
fn new() -> Self {
|
||||
Self {}
|
||||
|
|
@ -12,20 +14,672 @@ impl Target for AsmGen {
|
|||
fn get_int_ext(&self) -> &'static str {
|
||||
"s"
|
||||
}
|
||||
fn write_code(&mut self, program: &crate::parser::ast::Program, path: &std::path::Path) -> anyhow::Result<()> {
|
||||
let mut f = std::fs::File::open(path)?;
|
||||
fn write_code(&mut self, program: &crate::parser::ast::Program, f: &mut File) -> anyhow::Result<()> {
|
||||
writeln!(f, "bits 64")?;
|
||||
writeln!(f, "global _start")?;
|
||||
writeln!(f, "section .text")?;
|
||||
|
||||
writeln!(f, "section .rodata")?;
|
||||
for (name, constant) in &program.const_vars {
|
||||
writeln!(f, "{name}:")?;
|
||||
writeln!(f, "{}", RUNTIME_CODE)?;
|
||||
for item in &program.ast.0 {
|
||||
match item {
|
||||
Ast::Statement(stat) => {
|
||||
match stat.inner() {
|
||||
Statement::Fn(func) => self.write_func(program, f, func.clone(), stat.loc().clone())?,
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
writeln!(f, "section .data")?;
|
||||
self.write_constants(program, f)?;
|
||||
self.write_literals(program, f)?;
|
||||
writeln!(f, "section .data")?;
|
||||
self.write_statics(program, f)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
fn compile(&mut self, _from: &std::path::Path, _to: &std::path::Path) -> anyhow::Result<()> {
|
||||
fn compile(&mut self, from: &std::path::Path, to: &std::path::Path) -> anyhow::Result<()> {
|
||||
let mut cmd = std::process::Command::new("nasm");
|
||||
let cmd = cmd.args(&[
|
||||
"-felf64",
|
||||
"-o",
|
||||
to.to_string_lossy().to_string().as_str(),
|
||||
from.to_string_lossy().to_string().as_str(),
|
||||
]);
|
||||
info!("Running: {} {}", cmd.get_program().to_string_lossy(), cmd.get_args().map(|f| f.to_string_lossy().to_string()).collect::<Vec<String>>().join(" "));
|
||||
cmd.output()?;
|
||||
Ok(())
|
||||
}
|
||||
fn link(&mut self, _from: Vec<std::path::PathBuf>, _to: &std::path::Path) -> anyhow::Result<()> {
|
||||
fn link(&mut self, from: Vec<std::path::PathBuf>, to: &std::path::Path) -> anyhow::Result<()> {
|
||||
let mut cmd = std::process::Command::new("ld");
|
||||
cmd.args(&[
|
||||
"-o",
|
||||
to.to_string_lossy().to_string().as_str(),
|
||||
]);
|
||||
|
||||
for item in &from {
|
||||
cmd.arg(item.to_string_lossy().to_string().as_str());
|
||||
}
|
||||
info!("Running: {} {}", cmd.get_program().to_string_lossy(), cmd.get_args().map(|f| f.to_string_lossy().to_string()).collect::<Vec<String>>().join(" "));
|
||||
cmd.output()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// also used for args
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum VarMapT {
|
||||
Stack(usize, Type),
|
||||
}
|
||||
|
||||
pub struct FunctionCtx {
|
||||
vars: HashMap<Ident, VarMapT>,
|
||||
stack_offset: usize,
|
||||
used_registers: usize,
|
||||
loop_level: usize, // used for loops
|
||||
if_level: usize, // used for if stats
|
||||
cmp_level: usize, // used for logical comparisons
|
||||
pub emit_short_circuit_label: bool,
|
||||
pub is_last_item: bool,
|
||||
|
||||
}
|
||||
|
||||
impl FunctionCtx {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
vars: Default::default(),
|
||||
stack_offset: 0,
|
||||
used_registers: 0,
|
||||
loop_level: 0,
|
||||
if_level: 0,
|
||||
cmp_level: 0,
|
||||
emit_short_circuit_label: true,
|
||||
is_last_item: false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_stack(&mut self, name: &Ident, size: usize, typ: Type) -> usize {
|
||||
let offset = self.stack_offset;
|
||||
self.vars.insert(name.clone(), VarMapT::Stack(self.stack_offset, typ));
|
||||
self.stack_offset += size;
|
||||
offset
|
||||
}
|
||||
|
||||
pub fn get(&self, name: &Ident) -> Option<&VarMapT> {
|
||||
self.vars.get(name)
|
||||
}
|
||||
pub fn get_stack_offset(&self) -> usize {
|
||||
self.stack_offset
|
||||
}
|
||||
pub fn register_id_to_str(&self, id: usize) -> &str {
|
||||
match id {
|
||||
0 => "rdi",
|
||||
1 => "rsi",
|
||||
2 => "rdx",
|
||||
3 => "rcx",
|
||||
4 => "r8",
|
||||
5 => "r9",
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
pub fn inc_loop_level(&mut self) -> usize {
|
||||
self.loop_level += 1;
|
||||
self.loop_level
|
||||
}
|
||||
pub fn dec_loop_level(&mut self) -> usize {
|
||||
self.loop_level -= 1;
|
||||
self.loop_level
|
||||
}
|
||||
pub fn loop_level(&self) -> usize {
|
||||
self.loop_level
|
||||
}
|
||||
pub fn inc_if_level(&mut self) -> usize {
|
||||
self.if_level += 1;
|
||||
self.if_level
|
||||
}
|
||||
pub fn dec_if_level(&mut self) -> usize {
|
||||
self.if_level -= 1;
|
||||
self.if_level
|
||||
}
|
||||
pub fn if_level(&self) -> usize {
|
||||
self.if_level
|
||||
}
|
||||
pub fn inc_cmp_level(&mut self) -> usize {
|
||||
self.if_level += 1;
|
||||
self.if_level
|
||||
}
|
||||
pub fn dec_cmp_level(&mut self) -> usize {
|
||||
self.if_level -= 1;
|
||||
self.if_level
|
||||
}
|
||||
pub fn cmp_level(&self) -> usize {
|
||||
self.cmp_level
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl AsmGen {
|
||||
pub fn write_func(&self, program: &Program, f: &mut File, func: Function, loc: Loc) -> anyhow::Result<()> {
|
||||
if let Some(body) = &func.body {
|
||||
let mut fc = FunctionCtx::new();
|
||||
let name = if let Some(struct_name) = &func.struct_name {
|
||||
format!("{}${}", struct_name, func.name)
|
||||
} else {
|
||||
func.name.to_string()
|
||||
};
|
||||
writeln!(f, "{}: ; {} {}", name, loc, func.get_full_name_pretty())?;
|
||||
if body.0.is_empty() {
|
||||
writeln!(f, " ret")?;
|
||||
} else {
|
||||
let mut buf: Vec<u8> = Vec::new();
|
||||
let mut last_item = None;
|
||||
for (i, param) in func.params.iter().enumerate() {
|
||||
let typ = param.1.clone();
|
||||
let typ = typ.inner().clone();
|
||||
let offset = fc.insert_stack(¶m.0.clone(), typ.size_of(program)?, typ.clone());
|
||||
|
||||
writeln!(&mut buf, " mov [rsp+{offset}], {} ; func arg", fc.register_id_to_str(i))?;
|
||||
}
|
||||
let body = func.body.expect("Safe as its checked already").0;
|
||||
for (i, item) in body.iter().enumerate() {
|
||||
if i == body.len() - 1 {
|
||||
fc.is_last_item = true;
|
||||
}
|
||||
self.write_ast(program, &mut buf, &mut fc, item)?;
|
||||
last_item = Some(item.clone());
|
||||
}
|
||||
|
||||
if fc.stack_offset > 0 {
|
||||
writeln!(f, " sub rsp, {}", fc.stack_offset)?;
|
||||
}
|
||||
f.write(&buf)?;
|
||||
if fc.stack_offset > 0 {
|
||||
writeln!(f, " add rsp, {}", fc.stack_offset)?;
|
||||
}
|
||||
match last_item {
|
||||
Some(Ast::Expr(expr)) => {
|
||||
match expr.inner() {
|
||||
Expr::Return(_) => (),
|
||||
_ => writeln!(f, " ret")?,
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
// while writing the return expr, it changes is_last_item to false if it didnt write ret
|
||||
// and it was the last item in a body
|
||||
if !fc.is_last_item {
|
||||
writeln!(f, " ret")?;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
writeln!(f, " ret")?;
|
||||
}
|
||||
writeln!(f, "\n")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
pub fn write_ast(&self, program: &Program, f: &mut impl Write, fc: &mut FunctionCtx, ast: &Ast) -> anyhow::Result<()> {
|
||||
match ast {
|
||||
Ast::Expr(expr) => self.write_expr(program, f, fc, expr.inner())?,
|
||||
Ast::Statement(stat) => self.write_stat(program, f, fc, stat.inner())?,
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
pub fn write_expr(&self, program: &Program, f: &mut impl Write, fc: &mut FunctionCtx, expr: &Expr) -> anyhow::Result<()> {
|
||||
match expr {
|
||||
Expr::Cast { .. } => (),
|
||||
Expr::Literal(id, val) => {
|
||||
match val {
|
||||
Literal::Ident(_) => unreachable!(),
|
||||
Literal::Array(_) |
|
||||
Literal::String(_) |
|
||||
Literal::ArrayRepeat { .. } => {
|
||||
writeln!(f, " lea rax, [rel mcl_lit_{id}]")?;
|
||||
}
|
||||
Literal::Bool(v) => {
|
||||
writeln!(f, " mov rax, {} ; {}", *v as u8, v)?;
|
||||
}
|
||||
Literal::Number(_) |
|
||||
Literal::Char(_) => {
|
||||
writeln!(f, " mov rax, [rel mcl_lit_{id}]")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Expr::Struct(id, strct) => {
|
||||
writeln!(f, " lea r10, [rel mcl_lit_{id}]")?;
|
||||
let strct_t = program.structs.get(&strct.path.0[0]).unwrap();
|
||||
for (name, expr) in &strct.fields {
|
||||
self.write_expr(program, f, fc, expr.inner())?;
|
||||
let offset = strct_t.inner().get_offset_of(program, name)?;
|
||||
writeln!(f, " mov [r10+{offset}], rax")?;
|
||||
}
|
||||
}
|
||||
Expr::PtrFieldAccess { left, right, offset } => {
|
||||
self.write_expr(program, f, fc, left.clone().unwrap().inner())?;
|
||||
writeln!(f, " add rax, {offset} ; ->{:?}", right.inner())?;
|
||||
},
|
||||
Expr::FieldAccess { left, right, offset } => {
|
||||
self.write_expr(program, f, fc, left.clone().unwrap().inner())?;
|
||||
writeln!(f, " mov rax, [rel rax] ; .{:?}", right.inner())?;
|
||||
writeln!(f, " add rax, {offset} ; .{:?}", right.inner())?;
|
||||
},
|
||||
Expr::InfLoop { body } => {
|
||||
let sl = fc.inc_loop_level();
|
||||
writeln!(f, ".L{sl}_test: ; inf loop (named test for tehnical reason)")?;
|
||||
for item in &body.0 {
|
||||
self.write_ast(program, f, fc, item)?;
|
||||
}
|
||||
writeln!(f, ".L{sl}_end: ; inf loop")?;
|
||||
|
||||
}
|
||||
Expr::ForLoop { init, test, on_loop, body } => {
|
||||
let sl = fc.inc_loop_level();
|
||||
writeln!(f, ".L{sl}_init: ; for loop")?;
|
||||
self.write_ast(program, f, fc, &init)?;
|
||||
writeln!(f, ".L{sl}_test: ; for loop")?;
|
||||
writeln!(f, " xor rax, rax")?;
|
||||
self.write_expr(program, f, fc, &test.inner())?;
|
||||
writeln!(f, " test rax, rax")?;
|
||||
writeln!(f, " jz .L{sl}_end")?;
|
||||
writeln!(f, ".L{sl}_on_loop: ; for loop")?;
|
||||
self.write_expr(program, f, fc, &on_loop.inner())?;
|
||||
for item in &body.0 {
|
||||
self.write_ast(program, f, fc, item)?;
|
||||
}
|
||||
writeln!(f, ".L{sl}_end: ; for loop")?;
|
||||
}
|
||||
Expr::WhileLoop { test, body } => {
|
||||
let sl = fc.inc_loop_level();
|
||||
writeln!(f, ".L{sl}_test: ; while loop")?;
|
||||
writeln!(f, " xor rax, rax")?;
|
||||
self.write_expr(program, f, fc, &test.inner())?;
|
||||
writeln!(f, " test rax, rax")?;
|
||||
writeln!(f, " jz .L{sl}_end")?;
|
||||
for item in &body.0 {
|
||||
self.write_ast(program, f, fc, item)?;
|
||||
}
|
||||
writeln!(f, ".L{sl}_end: ; while loop")?;
|
||||
}
|
||||
Expr::Continue => {
|
||||
let sl = fc.loop_level();
|
||||
writeln!(f, " jmp .L{sl}_test ; continue")?;
|
||||
}
|
||||
Expr::Break => {
|
||||
let sl = fc.loop_level();
|
||||
writeln!(f, " jmp .L{sl}_end ; break")?;
|
||||
}
|
||||
Expr::If(ifs) => {
|
||||
let cl = fc.inc_if_level();
|
||||
writeln!(f, " xor rax, rax")?;
|
||||
self.write_expr(program, f, fc, ifs.test.inner())?;
|
||||
writeln!(f, " test rax, rax")?;
|
||||
if ifs.else_if.is_some() {
|
||||
writeln!(f, " jz .C{cl}_branch0")?;
|
||||
} else {
|
||||
writeln!(f, " jz .C{cl}_end")?;
|
||||
}
|
||||
for item in &ifs.body.0 {
|
||||
self.write_ast(program, f, fc, item)?;
|
||||
}
|
||||
self.write_expr(program, f, fc, ifs.test.inner())?;
|
||||
if ifs.else_if.is_some() {
|
||||
writeln!(f, " jmp .C{cl}_end")?;
|
||||
}
|
||||
fn x(slf: &AsmGen, program: &Program, f: &mut impl Write, fc: &mut FunctionCtx, els: &Option<IfBranchExpr>, depth: usize) -> anyhow::Result<()> {
|
||||
let cl = fc.if_level();
|
||||
if let Some(els) = els {
|
||||
match els {
|
||||
IfBranchExpr::Else(els) => {
|
||||
for item in &els.0 {
|
||||
writeln!(f, ".C{cl}_branch{depth}: ; if")?;
|
||||
slf.write_ast(program, f, fc, item)?;
|
||||
}
|
||||
}
|
||||
IfBranchExpr::ElseIf(elsif) => {
|
||||
slf.write_expr(program, f, fc, elsif.test.inner())?;
|
||||
writeln!(f, " test rax, rax")?;
|
||||
if elsif.else_if.is_some() {
|
||||
writeln!(f, " jz .C{cl}_branch{}", depth + 1)?;
|
||||
} else {
|
||||
writeln!(f, " jz .C{cl}_end")?;
|
||||
}
|
||||
for item in &elsif.body.0 {
|
||||
slf.write_ast(program, f, fc, item)?;
|
||||
}
|
||||
writeln!(f, " jmp .C{cl}_end")?;
|
||||
x(slf, program, f, fc, &elsif.else_if, depth+1)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
x(self, program, f, fc, &ifs.else_if, 0)?;
|
||||
writeln!(f, ".C{cl}_end: ; if")?;
|
||||
}
|
||||
Expr::Group(grp) => {
|
||||
self.write_expr(program, f, fc, grp.inner())?;
|
||||
}
|
||||
Expr::Return(ret) => {
|
||||
if let Some(ret) = &**ret {
|
||||
self.write_expr(program, f, fc, ret.inner())?;
|
||||
}
|
||||
if !fc.is_last_item {
|
||||
writeln!(f, " ret")?;
|
||||
} else {
|
||||
fc.is_last_item = false;
|
||||
}
|
||||
}
|
||||
Expr::Call { path, params } => {
|
||||
for (i, param) in params.0.iter().enumerate() {
|
||||
self.write_expr(program, f, fc, param.inner())?;
|
||||
if i <= 5 {
|
||||
let reg = fc.register_id_to_str(i);
|
||||
writeln!(f, " mov {reg}, rax")?;
|
||||
} else {
|
||||
writeln!(f, " push rax")?;
|
||||
}
|
||||
}
|
||||
|
||||
writeln!(f, " call {}", path.inner().unwrap_path().display_asm_compat())?;
|
||||
}
|
||||
Expr::UnOp { typ, right } => {
|
||||
self.write_expr(program, f, fc, right.inner())?;
|
||||
match typ {
|
||||
Punctuation::Not => {
|
||||
writeln!(f, " test rax, rax ; logical not")?;
|
||||
writeln!(f, " sete al")?;
|
||||
writeln!(f, " movzx rax, al")?;
|
||||
},
|
||||
Punctuation::Plus => {
|
||||
writeln!(f, " mov rdx, rax ; +x")?;
|
||||
writeln!(f, " sar rdx, 63")?;
|
||||
writeln!(f, " xor rax, rdx")?;
|
||||
writeln!(f, " sub rax, rdx")?;
|
||||
},
|
||||
Punctuation::Minus => {
|
||||
writeln!(f, " neg rax ; -x")?;
|
||||
},
|
||||
Punctuation::Ampersand => {
|
||||
writeln!(f, " ; noop?")?;
|
||||
},
|
||||
Punctuation::Star => {
|
||||
writeln!(f, " ; noop deref")?;
|
||||
},
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
Expr::BinOp { typ, left, right, signed } => {
|
||||
self.write_expr(program, f, fc, left.inner())?;
|
||||
writeln!(f, " mov r10, rax")?;
|
||||
self.write_expr(program, f, fc, right.inner())?;
|
||||
match typ {
|
||||
Punctuation::Plus => {
|
||||
writeln!(f, " add rax, r10")?;
|
||||
},
|
||||
Punctuation::Minus => {
|
||||
writeln!(f, " sub rax, r10")?;
|
||||
},
|
||||
Punctuation::Div => {
|
||||
writeln!(f, " mov rdi, rax")?;
|
||||
writeln!(f, " mov rax, r10 ")?;
|
||||
if *signed {
|
||||
writeln!(f, " cqo")?;
|
||||
writeln!(f, " idiv rdi")?;
|
||||
} else {
|
||||
writeln!(f, " xor rdx, rdx")?;
|
||||
writeln!(f, " div rdi")?;
|
||||
}
|
||||
},
|
||||
Punctuation::Star => {
|
||||
writeln!(f, " mov rdi, rax")?;
|
||||
writeln!(f, " mov rax, r10 ")?;
|
||||
|
||||
if *signed {
|
||||
writeln!(f, " imul r10 ")?;
|
||||
} else {
|
||||
writeln!(f, " mul r10 ")?;
|
||||
}
|
||||
},
|
||||
Punctuation::Mod => {
|
||||
writeln!(f, " mov rdi, rax")?;
|
||||
writeln!(f, " mov rax, r10 ")?;
|
||||
if *signed {
|
||||
writeln!(f, " cqo")?;
|
||||
writeln!(f, " idiv rdi")?;
|
||||
} else {
|
||||
writeln!(f, " xor rdx, rdx")?;
|
||||
writeln!(f, " div rdi")?;
|
||||
}
|
||||
writeln!(f, " mov rax, rdx")?;
|
||||
},
|
||||
Punctuation::Shl => {
|
||||
writeln!(f, " shl r10, rax")?;
|
||||
},
|
||||
Punctuation::Shr => {
|
||||
writeln!(f, " shr r10, rax")?;
|
||||
},
|
||||
Punctuation::AndAnd => {
|
||||
let l = fc.cmp_level();
|
||||
let should_emit = fc.emit_short_circuit_label;
|
||||
self.write_expr(program, f, fc, left.inner())?;
|
||||
writeln!(f, " test rax, rax")?;
|
||||
writeln!(f, " jz .M{l}_false")?;
|
||||
fc.emit_short_circuit_label = false;
|
||||
self.write_expr(program, f, fc, right.inner())?;
|
||||
fc.emit_short_circuit_label = should_emit;
|
||||
if !should_emit {
|
||||
writeln!(f, " setnz al")?;
|
||||
writeln!(f, " movzx rax, al")?;
|
||||
writeln!(f, " jmp .M{l}_sc")?;
|
||||
writeln!(f, ".M{l}_true:")?;
|
||||
writeln!(f, " mov rax, 1")?;
|
||||
writeln!(f, ".M{l}_false:")?;
|
||||
writeln!(f, " xor rax, rax")?;
|
||||
writeln!(f, ".M{l}_sc:")?;
|
||||
fc.inc_cmp_level();
|
||||
}
|
||||
},
|
||||
Punctuation::OrOr => {
|
||||
let l = fc.cmp_level();
|
||||
let should_emit = fc.emit_short_circuit_label;
|
||||
self.write_expr(program, f, fc, left.inner())?;
|
||||
writeln!(f, " cmp rax, rax")?;
|
||||
writeln!(f, " jnz .M{l}_true")?;
|
||||
fc.emit_short_circuit_label = false;
|
||||
self.write_expr(program, f, fc, right.inner())?;
|
||||
fc.emit_short_circuit_label = should_emit;
|
||||
if !should_emit {
|
||||
writeln!(f, " setnz al")?;
|
||||
writeln!(f, " movzx rax, al")?;
|
||||
writeln!(f, " jmp .M{l}_sc")?;
|
||||
writeln!(f, ".M{l}_true:")?;
|
||||
writeln!(f, " mov rax, 1")?;
|
||||
writeln!(f, ".M{l}_false:")?;
|
||||
writeln!(f, " xor rax, rax")?;
|
||||
writeln!(f, ".M{l}_sc:")?;
|
||||
fc.inc_cmp_level();
|
||||
}
|
||||
},
|
||||
Punctuation::Ampersand => {},
|
||||
Punctuation::Or => {},
|
||||
Punctuation::Xor => {},
|
||||
Punctuation::AddEq => {},
|
||||
Punctuation::SubEq => {},
|
||||
Punctuation::DivEq => {},
|
||||
Punctuation::MulEq => {},
|
||||
Punctuation::ModEq => {},
|
||||
Punctuation::ShlEq => {},
|
||||
Punctuation::ShrEq => {},
|
||||
Punctuation::AndEq => {},
|
||||
Punctuation::OrEq => {},
|
||||
Punctuation::XorEq => {},
|
||||
Punctuation::Eq => {
|
||||
self.write_expr(program, f, fc, right.inner())?;
|
||||
let VarMapT::Stack(offset, _) = fc.get(&left.inner().unwrap_path().0.clone()[0]).unwrap();
|
||||
writeln!(f, "mov [rbx+{offset}], rax")?;
|
||||
},
|
||||
Punctuation::EqEq => {},
|
||||
Punctuation::Lt => {},
|
||||
Punctuation::Gt => {},
|
||||
Punctuation::Le => {},
|
||||
Punctuation::Ge => {},
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
Expr::Path(path) => {
|
||||
dbg!(&path);
|
||||
let ident = path.0.last().unwrap().clone();
|
||||
if let Some(var) = fc.get(&ident) {
|
||||
match var {
|
||||
VarMapT::Stack(offset, typ) => {
|
||||
match typ {
|
||||
Type::Builtin { .. } => writeln!(f, " lea rax, [rsp + {offset}]")?,
|
||||
_ => writeln!(f, " mov rax, [rsp + {offset}]")?,
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let Some(_) = program.get_const_var(&ident) {
|
||||
writeln!(f, " lea rax, [rel {ident}]")?;
|
||||
} else {
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
v => unreachable!("{v:?}")
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn write_stat(&self, program: &Program, f: &mut impl Write, fc: &mut FunctionCtx, stat: &Statement) -> anyhow::Result<()> {
|
||||
match stat {
|
||||
Statement::Let(lt) => {
|
||||
let typ = lt.typ.clone().unwrap();
|
||||
let loc = typ.loc().clone();
|
||||
let typ = typ.inner().clone();
|
||||
let offset = fc.insert_stack(<.name, typ.size_of(program)?, typ.clone());
|
||||
|
||||
if let Some(value) = <.val {
|
||||
self.write_expr(program, f, fc, value.inner())?;
|
||||
writeln!(f, " mov [rsp+{offset}], rax ; {loc} let {};", lt.name)?;
|
||||
}
|
||||
}
|
||||
_ => unreachable!()
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn write_constants(&self, program: &Program, f: &mut File) -> anyhow::Result<()> {
|
||||
for (name, constant) in &program.const_vars {
|
||||
writeln!(f, "{name}: ; const")?;
|
||||
let bytes = get_constant_data_as_bytes(program, &HashMap::new(), constant.val.clone(), false, false)?;
|
||||
fn x(bytes: &ConstDataTyp, f: &mut File) -> anyhow::Result<()> {
|
||||
match bytes {
|
||||
ConstDataTyp::Array(arr) => {
|
||||
for v in arr {
|
||||
x(v, f)?;
|
||||
}
|
||||
}
|
||||
ConstDataTyp::Bytes(bytes) => {
|
||||
write!(f, " db ")?;
|
||||
for (i, b) in bytes.into_iter().enumerate() {
|
||||
if i != 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
write!(f, "0x{:02x}", b)?;
|
||||
}
|
||||
writeln!(f, "")?;
|
||||
}
|
||||
ConstDataTyp::AddrOfFunc(name) |
|
||||
ConstDataTyp::AddrOfConst(name) |
|
||||
ConstDataTyp::AddrOfStatic(name) => {
|
||||
writeln!(f, " dq {name}")?;
|
||||
},
|
||||
ConstDataTyp::Variable(..) => unreachable!(),
|
||||
}
|
||||
/*
|
||||
|
||||
*/
|
||||
Ok(())
|
||||
}
|
||||
x(&bytes, f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn write_statics(&self, program: &Program, f: &mut File) -> anyhow::Result<()> {
|
||||
for (name, statc) in &program.static_vars {
|
||||
writeln!(f, "{name}: ; static")?;
|
||||
let bytes = get_constant_data_as_bytes(program, &HashMap::new(), statc.val.clone(), false, false)?;
|
||||
fn x(bytes: &ConstDataTyp, f: &mut File) -> anyhow::Result<()> {
|
||||
match bytes {
|
||||
ConstDataTyp::Array(arr) => {
|
||||
for v in arr {
|
||||
x(v, f)?;
|
||||
}
|
||||
}
|
||||
ConstDataTyp::Bytes(bytes) => {
|
||||
write!(f, " db ")?;
|
||||
for (i, b) in bytes.into_iter().enumerate() {
|
||||
if i != 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
write!(f, "0x{:02x}", b)?;
|
||||
}
|
||||
writeln!(f, "")?;
|
||||
}
|
||||
ConstDataTyp::AddrOfFunc(name) |
|
||||
ConstDataTyp::AddrOfConst(name) |
|
||||
ConstDataTyp::AddrOfStatic(name) => {
|
||||
writeln!(f, " dq {name}")?;
|
||||
},
|
||||
ConstDataTyp::Variable(..) => unreachable!(),
|
||||
}
|
||||
/*
|
||||
|
||||
*/
|
||||
Ok(())
|
||||
}
|
||||
x(&bytes, f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn write_literals(&self, program: &Program, f: &mut File) -> anyhow::Result<()> {
|
||||
fn w(bytes: ConstDataTyp, f: &mut File) -> anyhow::Result<()> {
|
||||
match bytes {
|
||||
ConstDataTyp::Array(arr) => {
|
||||
for v in arr {
|
||||
w(v, f)?;
|
||||
}
|
||||
}
|
||||
ConstDataTyp::Bytes(bytes) => {
|
||||
write!(f, " db ")?;
|
||||
for (i, b) in bytes.into_iter().enumerate() {
|
||||
if i != 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
write!(f, "0x{:02x}", b)?;
|
||||
}
|
||||
writeln!(f, "")?;
|
||||
}
|
||||
ConstDataTyp::AddrOfFunc(name) |
|
||||
ConstDataTyp::AddrOfConst(name) |
|
||||
ConstDataTyp::AddrOfStatic(name) => {
|
||||
writeln!(f, " dq {name}")?;
|
||||
},
|
||||
ConstDataTyp::Variable(name, size) => {
|
||||
writeln!(f, " resb {size} ; {name}")?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
for lit in &program.literals {
|
||||
writeln!(f, "mcl_lit_{}:", lit.0)?;
|
||||
w(get_constant_data_as_bytes(program, &HashMap::new(), LocBox::new(&Loc::default(), Expr::Literal(lit.0.clone(), lit.1.clone())), false, false)?, f)?;
|
||||
}
|
||||
for lit in &program.struct_literals {
|
||||
writeln!(f, "mcl_lit_{}:", lit.0)?;
|
||||
w(get_constant_data_as_bytes(program, &HashMap::new(), LocBox::new(&Loc::default(), Expr::Struct(lit.0.clone(), lit.1.clone())), false, false)?, f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
41
src/targets/x86_64/asmgen/linux/runtime.s
Normal file
41
src/targets/x86_64/asmgen/linux/runtime.s
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
; generated with godbolt: https://godbolt.org/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAMzwBtMA7AQwFtMQByARg9KtQYEAysib0QXACx8BBAKoBnTAAUAHpwAMvAFYTStJg1AB9U8lJL6yAngGVG6AMKpaAVxYMQAJlIOAMngMmABy7gBGmMQgAMw%2BAA6oCoS2DM5uHt6kCUk2AgFBoSwRUbEWmFa5DEIETMQEae6ePpaY1inVtQT5IeGRMc01dQ0ZA53dhcX9AJQWqK7EyOwcAPQAVADUACoAnnGY69tzxOtoWOsIkZik6yTrtKhM6OuG65iqrHH0AHTrq8sApBoAIL/LzRQLINxnf7RRwKAjoWh4MJfBAw7CAkFgiFQ/YwuEI2yo9GY0HghiQ1zQ2Hw/CCYnRDHAzFJABemGMBHWLG2Cl5olotAgrkCBAAHJznsRgMY0K5BNcRYIJVy%2BQoBbRjAx3NcAG6oPBPVarWrABRTdb/ADsACFMesHes2RyucRMAQYXbgY71m7gHh4ZEnXh2ZLiExVM8FCwIKCvOHVHGLTCACJO/liTXalie%2B2Ov0BghB51h/BRmNx4j4JOW6JpjS5735zD%2BwPHEuupLl2NeeNJGup9YN6JeoE%2Bgtt4Oh13oSNMaM9%2BOzgd1oeNsfN1tF9shl2%2BrgabuVg8r%2Bvr8ctwvF3dhsUO%2BcV3vEMU12tnkd5h0T7dTvfEACc94LpW/6voOw6jp%2B6x4FQ6wQKaspzIItbYEOFpVngb5wR2Uymgo/wAKw2g2BEpuejowXBCFysh6LrFw6FdoOEA4XhhE2lwhFkR%2BTYOpR8HSoh8pcnRXjobOWEsTeBC4dK%2BFEV4XHkXxsECTKNEiYy6zROhB6SaxcnsdESk8RuKlUYJGkoeskjoXe%2BnSbJZrsZIJmjj6/HUUhmmoQR6GAQ505OfJNoEW5pK8eW6z6gYNj0HBUE%2BnGaoanGiWOiAlq9qmTBxhAboyelDqZXGuW9vlEYzFlXhkeVGFVXGQh5cQSQNb26DNbOMxFY6lbNQebXxs1YqDcQzX/lMPUlU%2ByCJr21zHpx83VWwLAkNsaWRZNplQQV8wML67rrtaKYcDMtCcARvCeBwWikKgnCOE6RyLFl0Q8KQBCaGdMwANYgARGj6JwkjXd992cLwCggEDX23WdpBwLASBoCwcR0JE5CUKj6P0FEyDAFwBE%2BDQtDbtDEBhODYSBLU2ycB9NPMMQ2wAPJhNorRwx9qNsIIrMMLQ9Pw6QWBhK4wCOJm0PcLwWAsIYwDiCL%2BBum0uqYDLd1vK0rhFgzvCiuU4NImE4Ys84WDgwQxB4CwBukBrxBhIkmAppgCtGEiRjfTMVAGGaABqeCYAA7qzew3R9/CCCIYjsFIMiCIoKjqCLuhcPoisgKYsr6Mi0OQDMqBxJUMsALSs9EvCoE7ttYIXEAzC0bR2BADjDJ4XA%2BP4gQ9EUfTvVkiTJAInd6Nko8MOMvRRJnLeVB0QwuI0EjNOUXPtIMXR9xMg/z9v48H2Mu%2BzxIzcvQn52XWDIsPRw6yqGKABs5fP5I6zAMgyD0QRXxeHBXAhBbhkgYrwOGWgph/QBkDC6HBQakBunde%2BUMYafV9tfDgXhb7IMhug%2BGUDHaRCSHYSQQA
|
||||
; removed "qword ptr" and replaced with "qword"
|
||||
syscall:
|
||||
mov ecx, edi
|
||||
mov r11, rdx
|
||||
movzx eax, sil
|
||||
xor edi, edi
|
||||
xor esi, esi
|
||||
xor edx, edx
|
||||
xor r10d, r10d
|
||||
xor r8d, r8d
|
||||
xor r9d, r9d
|
||||
test cl, cl
|
||||
je .L3
|
||||
mov rdi, QWORD [r11]
|
||||
cmp cl, 1
|
||||
je .L3
|
||||
mov rsi, QWORD [r11+8]
|
||||
cmp cl, 2
|
||||
je .L3
|
||||
mov rdx, QWORD [r11+16]
|
||||
cmp cl, 3
|
||||
je .L3
|
||||
mov r10, QWORD [r11+24]
|
||||
cmp cl, 4
|
||||
je .L3
|
||||
mov r8, QWORD [r11+32]
|
||||
cmp cl, 5
|
||||
je .L3
|
||||
mov r9, QWORD [r11+40]
|
||||
.L3:
|
||||
syscall
|
||||
ret
|
||||
global _start
|
||||
_start:
|
||||
xor rax, rax
|
||||
call main
|
||||
|
||||
mov rdi, rax
|
||||
mov rax, 60
|
||||
syscall
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// pub mod asmgen;
|
||||
pub mod cgen;
|
||||
pub mod asmgen;
|
||||
// pub mod cgen;
|
||||
// pub mod qbegen;
|
||||
// pub mod llvmgen;
|
||||
|
|
|
|||
|
|
@ -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,30 +1,29 @@
|
|||
use std::collections::HashMap;
|
||||
use std::{collections::HashMap, panic};
|
||||
|
||||
use anyhow::bail;
|
||||
|
||||
use crate::{common::{Loc, loc::LocBox}, parser::ast::{Ast, Program, Punctuation, TokenType, expr::*, statement::*, typ::Type}};
|
||||
use crate::{common::{Loc, loc::LocBox}, parser::ast::{Ast, Program, Punctuation, Scope, TokenType, expr::*, statement::*, typ::Type}, validator::predefined::get_builtin_from_name};
|
||||
|
||||
pub mod predefined;
|
||||
pub mod calculate_types;
|
||||
|
||||
pub fn validate_code(prog: &mut Program) -> anyhow::Result<()> {
|
||||
let Block(items) = prog.ast.clone();
|
||||
let Block(mut items) = prog.ast.clone();
|
||||
predefined::load_builtin(prog);
|
||||
collect_types_and_constants(prog, &items);
|
||||
collect_types_and_constants(prog, &mut items);
|
||||
check_that_types_exist_for_items(prog, &items)?;
|
||||
//dbg!(&prog.types);
|
||||
//dbg!(&prog.structs);
|
||||
//dbg!(&prog.enums);
|
||||
//dbg!(&prog.member_functions);
|
||||
//dbg!(&prog.functions);
|
||||
for item in items.iter() {
|
||||
for item in items.iter_mut() {
|
||||
match item {
|
||||
Ast::Statement(stat) => validate_stat(prog, &stat, CurrentState::Outside)?,
|
||||
Ast::Statement(stat) => validate_stat(prog, stat, CurrentState::Outside)?,
|
||||
Ast::Expr(_) => unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
prog.ast.0 = items;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -37,9 +36,9 @@ enum CurrentState {
|
|||
|
||||
|
||||
|
||||
fn validate_stat(prog: &mut Program, stat: &LocBox<Statement>, current_state: CurrentState) -> anyhow::Result<()> {
|
||||
match stat.inner() {
|
||||
Statement::Fn(func) => validate_fn(prog, &func)?,
|
||||
fn validate_stat(prog: &mut Program, stat: &mut LocBox<Statement>, current_state: CurrentState) -> anyhow::Result<()> {
|
||||
match stat.inner_mut() {
|
||||
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");
|
||||
|
|
@ -55,56 +54,75 @@ fn validate_stat(prog: &mut Program, stat: &LocBox<Statement>, current_state: Cu
|
|||
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());
|
||||
fn validate_stat_let(prog: &mut Program, lt: &mut Let) -> anyhow::Result<()> {
|
||||
if let Some(val) = &mut lt.val && let Some(t) = &mut lt.typ {
|
||||
let val_t = validate_expr(prog, val.inner_mut())?.unwrap();
|
||||
if val_t != *t.inner_mut() {
|
||||
lerror!(t.loc(), "Cannot assign {val_t} to {}", t.inner_mut());
|
||||
bail!("")
|
||||
}
|
||||
}
|
||||
if let Some(val) = &mut lt.val && let None = &mut lt.typ {
|
||||
let Some(t) = validate_expr(prog, val.inner_mut())? else {
|
||||
lerror!(val.loc(), "Expected a type, go none");
|
||||
bail!("");
|
||||
};
|
||||
lt.typ = Some(LocBox::new(val.loc(), t));
|
||||
}
|
||||
if let Some(scope) = &mut prog.scope {
|
||||
scope.vars.insert(lt.name.clone(), LocBox::new(&Default::default(), lt.clone()));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_ast(prog: &mut Program, ast: &Ast) -> anyhow::Result<Option<Type>> {
|
||||
fn validate_ast(prog: &mut Program, ast: &mut Ast) -> anyhow::Result<Option<Type>> {
|
||||
match ast {
|
||||
Ast::Expr(expr) => {
|
||||
validate_expr(prog, &expr.inner())
|
||||
validate_expr(prog, expr.inner_mut())
|
||||
}
|
||||
Ast::Statement(stat) => {
|
||||
validate_stat(prog, &stat, CurrentState::InFunc)?;
|
||||
validate_stat(prog, stat, CurrentState::InFunc)?;
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn validate_expr(prog: &mut Program, expr: &Expr) -> anyhow::Result<Option<Type>> {
|
||||
pub fn validate_expr(prog: &mut Program, expr: &mut 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())
|
||||
if let Some(expr) = &mut**ret {
|
||||
validate_expr(prog, expr.inner_mut())
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
Expr::Struct { path, fields } => {
|
||||
Expr::Struct(id, strct) => {
|
||||
// this is probably fucked so fix this later
|
||||
let name = path.0.last().expect("Paths always have at least one part");
|
||||
let name = strct.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())?;
|
||||
for field in strct.fields.iter_mut() {
|
||||
validate_expr(prog, field.1.inner_mut())?;
|
||||
}
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
let mut hasher = DefaultHasher::new();
|
||||
(*strct).hash(&mut hasher);
|
||||
let hash = hasher.finish();
|
||||
*id = hash.to_string();
|
||||
|
||||
prog.struct_literals.insert(id.clone(), strct.clone());
|
||||
|
||||
Ok(Some(typ))
|
||||
},
|
||||
Expr::If(ifs) => {
|
||||
validate_expr(prog, ifs.test.inner())?;
|
||||
for item in &ifs.body.0 {
|
||||
validate_expr(prog, ifs.test.inner_mut())?;
|
||||
for item in ifs.body.0.iter_mut() {
|
||||
validate_ast(prog, item)?;
|
||||
}
|
||||
Ok(None)
|
||||
|
|
@ -113,19 +131,42 @@ pub fn validate_expr(prog: &mut Program, expr: &Expr) -> anyhow::Result<Option<T
|
|||
// TODO: Path hell TBD
|
||||
Ok(Some(Type::Owned(path.0.last().unwrap().clone())))
|
||||
}
|
||||
Expr::Group(group) => validate_expr(prog, &group.inner()),
|
||||
Expr::Group(group) => validate_expr(prog, group.inner_mut()),
|
||||
Expr::Call { path, params } => {
|
||||
let loc = path.loc();
|
||||
let Expr::Path(path) = path.inner() else {
|
||||
let loc = path.loc().clone();
|
||||
let Expr::Path(path) = path.inner_mut() else {
|
||||
panic!("fml");
|
||||
};
|
||||
|
||||
let func;
|
||||
match path.0.len() {
|
||||
1 => {
|
||||
let f = prog.functions.get(&path.0[0]);
|
||||
let f = prog.functions.get(&path.0[0]).cloned();
|
||||
match f {
|
||||
Some(f) => func = f.clone(),
|
||||
Some(func) => {
|
||||
for (i, param) in params.0.iter_mut().enumerate() {
|
||||
let ft = func.inner().params[i].1.inner().clone();
|
||||
let t = validate_expr(prog, param.inner_mut())?.clone();
|
||||
match t {
|
||||
Some(t) => {
|
||||
let t = t.get_variable_type(prog)?;
|
||||
let ft = ft.get_variable_type(prog)?;
|
||||
if t != ft {
|
||||
lerror!(param.loc(), "expected {ft:?}, got {t:?}");
|
||||
bail!("owo")
|
||||
}
|
||||
}
|
||||
None => {
|
||||
lerror!(param.loc(), "expected {ft}, got Nothing");
|
||||
bail!("nya")
|
||||
},
|
||||
}
|
||||
}
|
||||
if let Some(t) = &func.inner().ret_type {
|
||||
Ok(Some(t.inner().clone()))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
},
|
||||
None => {
|
||||
lerror!(loc, "Could not find function {}", path);
|
||||
panic!("")
|
||||
|
|
@ -134,9 +175,34 @@ pub fn validate_expr(prog: &mut Program, expr: &Expr) -> anyhow::Result<Option<T
|
|||
}
|
||||
2 => {
|
||||
let s = prog.member_functions.get(&path.0[0]).unwrap();
|
||||
let f = s.get(&path.0[1]);
|
||||
let f = s.get(&path.0[1]).cloned();
|
||||
match f {
|
||||
Some(f) => func = LocBox::new(loc, f.clone().inner().clone()),
|
||||
Some(func) => {
|
||||
for (i, param) in params.0.iter_mut().enumerate() {
|
||||
let ft = func.inner().params[i].1.inner().clone();
|
||||
let t = validate_expr(prog, param.inner_mut())?.clone();
|
||||
match t {
|
||||
Some(t) => {
|
||||
dbg!(&t);
|
||||
dbg!(&ft);
|
||||
if t.get_absolute_value(prog)? != ft.get_absolute_value(prog)? {
|
||||
lerror!(param.loc(), "expected {ft}, got {}", t);
|
||||
bail!("")
|
||||
}
|
||||
}
|
||||
None => {
|
||||
lerror!(param.loc(), "expected {ft}, got Nothing");
|
||||
bail!("")
|
||||
},
|
||||
}
|
||||
}
|
||||
if let Some(t) = &func.inner().ret_type {
|
||||
Ok(Some(t.inner().clone()))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
},
|
||||
None => {
|
||||
lerror!(loc, "Could not find function {}", path);
|
||||
panic!("")
|
||||
|
|
@ -147,16 +213,41 @@ pub fn validate_expr(prog: &mut Program, expr: &Expr) -> anyhow::Result<Option<T
|
|||
}
|
||||
|
||||
|
||||
for (i, param) in params.0.iter().enumerate() {
|
||||
let t = validate_expr(prog, param.inner())?;
|
||||
let ft = func.inner().params[i].1.inner();
|
||||
|
||||
}
|
||||
Expr::MethodCall { left, params } => {
|
||||
let var_t;
|
||||
let method_name;
|
||||
match left.inner_mut() {
|
||||
Expr::FieldAccess { left, right, .. } |
|
||||
Expr::PtrFieldAccess { left, right, .. } => {
|
||||
var_t = validate_expr(prog, left.clone().unwrap().inner_mut())?;
|
||||
let name = validate_expr(prog, right.inner_mut())?;
|
||||
match name.unwrap() {
|
||||
Type::Owned(name) => method_name = name,
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
_ => unreachable!()
|
||||
}
|
||||
|
||||
let Type::Owned(struct_name) = var_t.unwrap().get_absolute_value(prog)? else {
|
||||
panic!("fml");
|
||||
};
|
||||
|
||||
let mut strct = prog.member_functions.get_mut(&struct_name).unwrap().clone();
|
||||
let func = strct.get_mut(&method_name).unwrap();
|
||||
|
||||
for (i, param) in params.0.iter_mut().enumerate() {
|
||||
let t = validate_expr(prog, param.inner_mut())?;
|
||||
let ft = func.inner_mut().params[i].1.inner_mut();
|
||||
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()))
|
||||
if let Some(t) = &mut func.inner_mut().ret_type {
|
||||
Ok(Some(t.inner_mut().clone()))
|
||||
} else {
|
||||
Ok(None)
|
||||
|
||||
|
|
@ -164,24 +255,34 @@ pub fn validate_expr(prog: &mut Program, expr: &Expr) -> anyhow::Result<Option<T
|
|||
}
|
||||
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_expr(prog, test.inner_mut())?;
|
||||
let _ = validate_expr(prog, on_loop.inner_mut())?;
|
||||
for item in body.0.iter_mut() {
|
||||
let _ = validate_ast(prog, item)?;
|
||||
}
|
||||
Ok(None)
|
||||
},
|
||||
Expr::Cast { left, right } => {
|
||||
validate_expr(prog, left.inner())?;
|
||||
Ok(Some(right.inner().clone()))
|
||||
validate_expr(prog, left.inner_mut())?;
|
||||
Ok(Some(right.inner_mut().clone()))
|
||||
}
|
||||
Expr::Literal(lit) => {
|
||||
Expr::Literal(id, lit) => {
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
let mut hasher = DefaultHasher::new();
|
||||
(*lit).hash(&mut hasher);
|
||||
let hash = hasher.finish();
|
||||
*id = hash.to_string();
|
||||
|
||||
prog.literals.insert(id.clone(), lit.clone());
|
||||
|
||||
Ok(Some(lit.to_type(prog)?))
|
||||
}
|
||||
Expr::UnOp { typ, right } => {
|
||||
match typ {
|
||||
Punctuation::Not => {
|
||||
let t = validate_expr(prog, right.inner())?.unwrap();
|
||||
let t = validate_expr(prog, right.inner_mut())?.unwrap().get_absolute_value(prog)?;
|
||||
if !t.is_bool(prog) {
|
||||
lerror!(right.loc(), "Expected bool, got {t}");
|
||||
}
|
||||
|
|
@ -189,7 +290,7 @@ pub fn validate_expr(prog: &mut Program, expr: &Expr) -> anyhow::Result<Option<T
|
|||
}
|
||||
Punctuation::Minus |
|
||||
Punctuation::Plus => {
|
||||
let t = validate_expr(prog, right.inner())?.unwrap();
|
||||
let t = validate_expr(prog, right.inner_mut())?.unwrap().get_absolute_value(prog)?;
|
||||
if !t.is_numeric(prog) {
|
||||
lerror!(right.loc(), "Expected number, got {t}");
|
||||
}
|
||||
|
|
@ -197,11 +298,11 @@ pub fn validate_expr(prog: &mut Program, expr: &Expr) -> anyhow::Result<Option<T
|
|||
}
|
||||
|
||||
Punctuation::Ampersand => {
|
||||
let t = validate_expr(prog, right.inner())?.unwrap();
|
||||
let t = validate_expr(prog, right.inner_mut())?.unwrap().get_absolute_value(prog)?;
|
||||
Ok(Some(Type::Ref { inner: Box::new(t), mutable: false }))
|
||||
}
|
||||
Punctuation::Star => {
|
||||
let t = validate_expr(prog, right.inner())?.unwrap();
|
||||
let t = validate_expr(prog, right.inner_mut())?.unwrap().get_absolute_value(prog)?;
|
||||
if !t.is_ptr(prog) {
|
||||
lerror!(right.loc(), "Expected pointer, got {t}");
|
||||
}
|
||||
|
|
@ -214,7 +315,7 @@ pub fn validate_expr(prog: &mut Program, expr: &Expr) -> anyhow::Result<Option<T
|
|||
_ => unreachable!()
|
||||
}
|
||||
},
|
||||
Expr::BinOp { typ, left, right } => {
|
||||
Expr::BinOp { typ, left, right, signed } => {
|
||||
match typ {
|
||||
Punctuation::Ampersand |
|
||||
Punctuation::Or |
|
||||
|
|
@ -228,23 +329,24 @@ pub fn validate_expr(prog: &mut Program, expr: &Expr) -> anyhow::Result<Option<T
|
|||
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}");
|
||||
let t1 = validate_expr(prog, left.inner_mut())?.unwrap().get_absolute_value(prog)?;
|
||||
let t2 = validate_expr(prog, right.inner_mut())?.unwrap().get_absolute_value(prog)?;
|
||||
if !(t1.is_numeric(prog) || t1.is_ptr(prog)) {
|
||||
lerror!(right.loc(), "Expected number, got {t1}");
|
||||
}
|
||||
if !t2.is_numeric(prog) {
|
||||
lerror!(right.loc(), "Expected bool, got {t2}");
|
||||
if !(t2.is_numeric(prog) || t2.is_ptr(prog)) {
|
||||
lerror!(right.loc(), "Expected number, got {t2}");
|
||||
}
|
||||
match &t1 {
|
||||
Type::Builtin { name: _, size, .. } => t1_s = *size,
|
||||
_ => unreachable!()
|
||||
_ => unreachable!("1: {t1:?}\n2: {t2:?}")
|
||||
}
|
||||
|
||||
match &t2 {
|
||||
Type::Builtin { name: _, size, .. } => t2_s = *size,
|
||||
_ => unreachable!()
|
||||
}
|
||||
*signed = t1.is_signed(prog).expect("verified as numeric");
|
||||
if t2_s > t1_s {
|
||||
Ok(Some(t2))
|
||||
} else {
|
||||
|
|
@ -258,14 +360,15 @@ pub fn validate_expr(prog: &mut Program, expr: &Expr) -> anyhow::Result<Option<T
|
|||
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}");
|
||||
let t1 = validate_expr(prog, left.inner_mut())?.unwrap().get_absolute_value(prog)?;
|
||||
let t2 = validate_expr(prog, right.inner_mut())?.unwrap().get_absolute_value(prog)?;
|
||||
if !(t1.is_numeric(prog) || t1.is_ptr(prog)) {
|
||||
lerror!(right.loc(), "Expected number or pointer, got {t1}");
|
||||
}
|
||||
if !t2.is_bool(prog) {
|
||||
lerror!(right.loc(), "Expected bool, got {t2}");
|
||||
if !(t2.is_numeric(prog) || t2.is_ptr(prog)) {
|
||||
lerror!(right.loc(), "Expected number or pointer, got {t2}");
|
||||
}
|
||||
*signed = t1.is_signed(prog).expect("verified as numeric");
|
||||
Ok(Some(t1))
|
||||
}
|
||||
|
||||
|
|
@ -279,21 +382,22 @@ pub fn validate_expr(prog: &mut Program, expr: &Expr) -> anyhow::Result<Option<T
|
|||
Punctuation::AndEq |
|
||||
Punctuation::OrEq |
|
||||
Punctuation::XorEq => {
|
||||
let var = validate_expr(prog, left.inner())?.unwrap();
|
||||
let var = validate_expr(prog, left.inner_mut())?.unwrap();
|
||||
let var_t = var.get_absolute_value(prog)?;
|
||||
let val_t = validate_expr(prog, right.inner())?.unwrap();
|
||||
let val_t = validate_expr(prog, right.inner_mut())?.unwrap().get_absolute_value(prog)?;
|
||||
|
||||
if !(var_t.is_numeric(prog) && val_t.is_numeric(prog)) {
|
||||
if !((var_t.is_numeric(prog) || var_t.is_ptr(prog)) && (val_t.is_numeric(prog) || val_t.is_ptr(prog))) {
|
||||
lerror!(left.loc(), "Mismatched types, assigning {val_t} to {var_t}");
|
||||
bail!("");
|
||||
}
|
||||
|
||||
*signed = var_t.is_signed(prog).expect("verified as numeric");
|
||||
Ok(None)
|
||||
}
|
||||
Punctuation::Eq => {
|
||||
let var = validate_expr(prog, left.inner())?.unwrap();
|
||||
let var = validate_expr(prog, left.inner_mut())?.unwrap();
|
||||
let var_t = var.get_absolute_value(prog)?;
|
||||
let val_t = validate_expr(prog, right.inner())?.unwrap();
|
||||
let val_t = validate_expr(prog, right.inner_mut())?.unwrap().get_absolute_value(prog)?;
|
||||
|
||||
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}");
|
||||
|
|
@ -306,7 +410,7 @@ pub fn validate_expr(prog: &mut Program, expr: &Expr) -> anyhow::Result<Option<T
|
|||
}
|
||||
},
|
||||
Expr::ArrayIndex { name, index } => {
|
||||
let left = validate_expr(prog, name.inner())?;
|
||||
let left = validate_expr(prog, name.inner_mut())?;
|
||||
let Some(left) = left else {
|
||||
lerror!(name.loc(), "expected value, got nothing, cannot index nothing");
|
||||
bail!("")
|
||||
|
|
@ -332,7 +436,7 @@ pub fn validate_expr(prog: &mut Program, expr: &Expr) -> anyhow::Result<Option<T
|
|||
}
|
||||
Type::Owned(name) => {
|
||||
let t = prog.types.get(name).cloned();
|
||||
if let Some(t) = t {
|
||||
if let Some(t) = &t {
|
||||
f(prog, t.inner(), t.loc(), index)
|
||||
} else {
|
||||
lerror!(loc, "Unknown type {name}");
|
||||
|
|
@ -348,38 +452,39 @@ pub fn validate_expr(prog: &mut Program, expr: &Expr) -> anyhow::Result<Option<T
|
|||
}
|
||||
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();
|
||||
Expr::PtrFieldAccess { left, right, offset } |
|
||||
Expr::FieldAccess { left, right, offset } => {
|
||||
let left = validate_expr(prog, left.clone().unwrap().inner_mut())?;
|
||||
let right = validate_expr(prog, right.clone().inner_mut())?.unwrap();
|
||||
let Type::Owned(right) = right else {
|
||||
panic!()
|
||||
};
|
||||
match left.unwrap() {
|
||||
match left.unwrap().get_absolute_value(prog)? {
|
||||
Type::Owned(name) => {
|
||||
if let Some(strct) = prog.structs.get(&name) {
|
||||
for field in &strct.inner().fields {
|
||||
for field in strct.inner().fields.iter() {
|
||||
if field.0 == right {
|
||||
*offset = strct.inner().clone().get_offset_of(prog, &right)?;
|
||||
return Ok(Some(field.1.inner().clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => panic!()
|
||||
v => panic!("{v:?}"),
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
},
|
||||
Expr::WhileLoop { test, body } => {
|
||||
let _ = validate_expr(prog, test.inner())?;
|
||||
for item in &body.0 {
|
||||
let _ = validate_expr(prog, test.inner_mut())?;
|
||||
for item in body.0.iter_mut() {
|
||||
let _ = validate_ast(prog, item)?;
|
||||
}
|
||||
Ok(None)
|
||||
|
||||
},
|
||||
Expr::InfLoop { body } => {
|
||||
for item in &body.0 {
|
||||
for item in body.0.iter_mut() {
|
||||
let _ = validate_ast(prog, item)?;
|
||||
}
|
||||
Ok(None)
|
||||
|
|
@ -388,12 +493,14 @@ pub fn validate_expr(prog: &mut Program, expr: &Expr) -> anyhow::Result<Option<T
|
|||
}
|
||||
}
|
||||
|
||||
fn validate_fn(prog: &mut Program, func: &Function) -> anyhow::Result<()> {
|
||||
fn validate_fn(prog: &mut Program, func: &mut Function) -> anyhow::Result<()> {
|
||||
prog.scope = Some(Scope::default());
|
||||
for param in &func.params {
|
||||
validate_type(prog, ¶m.1)?;
|
||||
let t = validate_type(prog, ¶m.1)?;
|
||||
prog.curr_fn_args.insert(param.0.clone(), LocBox::new(&Loc::default(), t.clone()));
|
||||
}
|
||||
if let Some(body) = &func.body {
|
||||
for item in &body.0 {
|
||||
if let Some(body) = &mut func.body {
|
||||
for item in body.0.iter_mut() {
|
||||
validate_ast(prog, item)?;
|
||||
}
|
||||
}
|
||||
|
|
@ -401,12 +508,12 @@ fn validate_fn(prog: &mut Program, func: &Function) -> anyhow::Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_const_var(prog: &mut Program, var: &ConstVar) -> anyhow::Result<()> {
|
||||
fn validate_const_var(prog: &mut Program, var: &mut ConstVar) -> anyhow::Result<()> {
|
||||
validate_type(prog, &var.typ)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_static_var(prog: &mut Program, var: &StaticVar) -> anyhow::Result<()> {
|
||||
fn validate_static_var(prog: &mut Program, var: &mut StaticVar) -> anyhow::Result<()> {
|
||||
validate_type(prog, &var.typ)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -416,7 +523,7 @@ fn validate_enum(_: &mut Program, _: &Enum) -> anyhow::Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_struct(prog: &mut Program, strct: &Struct) -> anyhow::Result<()> {
|
||||
fn validate_struct(prog: &mut Program, strct: &mut 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);
|
||||
|
|
@ -465,7 +572,7 @@ fn check_that_types_exist_for_items(prog: &mut Program, items: &Vec<Ast>) -> any
|
|||
}
|
||||
Statement::Enum(_) => (),
|
||||
Statement::Struct(strct) => {
|
||||
for (name, t) in &strct.fields {
|
||||
for (name, t) in strct.fields.iter() {
|
||||
if let Err(_) = validate_type(prog, t) {
|
||||
lerror!(t.loc(), "Type '{}', of field, '{}.{name}' does not exist", t.inner(), strct.name);
|
||||
errored = true;
|
||||
|
|
@ -490,23 +597,26 @@ fn check_that_types_exist_for_items(prog: &mut Program, items: &Vec<Ast>) -> any
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_type(prog: &mut Program, typ: &LocBox<Type>) -> anyhow::Result<()> {
|
||||
fn f(prog: &mut Program, typ: &Type, loc: &Loc) -> anyhow::Result<()> {
|
||||
fn validate_type(prog: &mut Program, typ: &LocBox<Type>) -> anyhow::Result<Type> {
|
||||
fn f(prog: &mut Program, typ: &Type, loc: &Loc) -> anyhow::Result<Type> {
|
||||
match typ {
|
||||
Type::SizedArray { inner, .. } |
|
||||
Type::UnsizedArray { inner, .. } |
|
||||
Type::Ref { inner, .. } => f(prog, inner, loc),
|
||||
Type::Owned(typ) => {
|
||||
if prog.enums.get(typ).is_some() ||
|
||||
prog.types.get(typ).is_some() ||
|
||||
prog.structs.get(typ).is_some() {
|
||||
Ok(())
|
||||
Type::Owned(ident) => {
|
||||
if let Some(builtin) = get_builtin_from_name(&ident.0) {
|
||||
Ok(builtin)
|
||||
} else
|
||||
if prog.enums.get(ident).is_some() ||
|
||||
prog.types.get(ident).is_some() ||
|
||||
prog.structs.get(ident).is_some() {
|
||||
Ok(typ.clone())
|
||||
} else {
|
||||
lerror!(loc, "Could not find type '{}'", typ.0);
|
||||
lerror!(loc, "Could not find type '{}'", ident.0);
|
||||
bail!("")
|
||||
}
|
||||
}
|
||||
Type::Builtin { .. } => Ok(())
|
||||
Type::Builtin { .. } => Ok(typ.clone())
|
||||
}
|
||||
}
|
||||
f(prog, typ.inner(), typ.loc())
|
||||
|
|
@ -514,32 +624,33 @@ fn validate_type(prog: &mut Program, typ: &LocBox<Type>) -> anyhow::Result<()> {
|
|||
|
||||
|
||||
|
||||
fn collect_types_and_constants(prog: &mut Program, items: &Vec<Ast>) {
|
||||
for item in items {
|
||||
fn collect_types_and_constants(prog: &mut Program, items: &mut Vec<Ast>) {
|
||||
for item in items.iter_mut() {
|
||||
match item {
|
||||
Ast::Statement(stat) => {
|
||||
match stat.inner() {
|
||||
let loc = stat.loc().clone();
|
||||
match stat.inner_mut() {
|
||||
Statement::Fn(func)=> {
|
||||
if let Some(struct_name) = &func.struct_name {
|
||||
if let Some(v) = prog.member_functions.get_mut(&struct_name) {
|
||||
v.insert(func.name.clone(), LocBox::new(stat.loc(), func.clone()));
|
||||
v.insert(func.name.clone(), LocBox::new(&loc, func.clone()));
|
||||
} else {
|
||||
let mut v = HashMap::new();
|
||||
v.insert(func.name.clone(), LocBox::new(stat.loc(), func.clone()));
|
||||
v.insert(func.name.clone(), LocBox::new(&loc, func.clone()));
|
||||
prog.member_functions.insert(struct_name.clone(), v);
|
||||
}
|
||||
} else {
|
||||
prog.functions.insert(func.name.clone(), LocBox::new(stat.loc(), func.clone()));
|
||||
prog.functions.insert(func.name.clone(), LocBox::new(&loc, func.clone()));
|
||||
}
|
||||
}
|
||||
Statement::Enum(enm) => {
|
||||
prog.enums.insert(enm.name.clone(), LocBox::new(stat.loc(), enm.clone()));
|
||||
prog.enums.insert(enm.name.clone(), LocBox::new(&loc, enm.clone()));
|
||||
}
|
||||
Statement::Struct(strct) => {
|
||||
prog.structs.insert(strct.name.clone(), LocBox::new(stat.loc(), strct.clone()));
|
||||
prog.structs.insert(strct.name.clone(), LocBox::new(&loc, strct.clone()));
|
||||
}
|
||||
Statement::TypeAlias(alias) => {
|
||||
let typ = alias.clone().typ.inner().clone();
|
||||
let typ = alias.clone().typ.inner_mut().clone();
|
||||
prog.types.insert(alias.name.clone(), LocBox::new(stat.loc(), typ));
|
||||
}
|
||||
Statement::Let { .. } => (),
|
||||
|
|
@ -551,7 +662,33 @@ fn collect_types_and_constants(prog: &mut Program, items: &Vec<Ast>) {
|
|||
},
|
||||
}
|
||||
}
|
||||
Ast::Expr(_) => unreachable!()
|
||||
Ast::Expr(expr) => {
|
||||
match expr.inner_mut() {
|
||||
Expr::Literal(id, val) => {
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
let mut hasher = DefaultHasher::new();
|
||||
(*val).hash(&mut hasher);
|
||||
let hash = hasher.finish();
|
||||
*id = hash.to_string();
|
||||
|
||||
prog.literals.insert(id.clone(), val.clone());
|
||||
}
|
||||
Expr::Struct(id, strct) => {
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
let mut hasher = DefaultHasher::new();
|
||||
(*strct).hash(&mut hasher);
|
||||
let hash = hasher.finish();
|
||||
*id = hash.to_string();
|
||||
|
||||
prog.struct_literals.insert(id.clone(), strct.clone());
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,13 @@ lazy_static!(
|
|||
].into();
|
||||
);
|
||||
|
||||
pub fn get_builtin_from_name(name: &str) -> Option<Type> {
|
||||
if let Some(t) = TYPES_RAW.get(name) {
|
||||
Some(Type::Builtin { name: name.to_string(), size: t.0 as u8, signed: t.1 })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_builtin(prog: &mut Program) {
|
||||
let loc = Loc::new("(internal)", 0, 0);
|
||||
|
|
|
|||
38
test.mcl
38
test.mcl
|
|
@ -1,21 +1,47 @@
|
|||
type str = [u8];
|
||||
|
||||
|
||||
|
||||
struct Foo {
|
||||
a: usize,
|
||||
b: &str
|
||||
}
|
||||
|
||||
fn Foo.new(a: usize, b: &str) -> Foo {
|
||||
return Foo {
|
||||
fn Foo.new(a: usize, b: &str) -> &Foo {
|
||||
return &Foo {
|
||||
a: a,
|
||||
b: b
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
fn main() -> i32 {
|
||||
let obj = Foo::new();
|
||||
|
||||
fn print(s: &str) {
|
||||
// do nothign for now
|
||||
}
|
||||
|
||||
fn mul(n: usize, n2: usize) -> usize {
|
||||
return n * n2;
|
||||
}
|
||||
|
||||
fn main() -> i32 {
|
||||
let obj = Foo::new(1, "owo");
|
||||
obj->b;
|
||||
let owo = "ahahaha";
|
||||
loop {
|
||||
print(owo);
|
||||
}
|
||||
|
||||
for (let i = 0; i < 10; i += 1) {
|
||||
print("nyaaa");
|
||||
if (i > 7) {
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
print("cant see me!");
|
||||
}
|
||||
while (true) {
|
||||
mul(1);
|
||||
}
|
||||
}
|
||||
|
||||
const FOO: usize = main;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user