:3
This commit is contained in:
parent
06d8c1b0f3
commit
158b76fe39
|
|
@ -27,7 +27,7 @@ impl Loc {
|
|||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct LocBox<T: Clone + Debug> {
|
||||
inner: T,
|
||||
loc: Loc
|
||||
|
|
|
|||
|
|
@ -25,8 +25,9 @@ fn main() -> anyhow::Result<()> {
|
|||
info!("Parsing {file}");
|
||||
let mut prog = mclangc::parser::parse_program(tokens)?;
|
||||
info!("Validating {file}");
|
||||
dbg!(&prog);
|
||||
mclangc::validator::validate_code(&mut prog)?;
|
||||
// dbg!(&prog);
|
||||
//dbg!(&prog);
|
||||
progs.push((fp, prog));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use std::{collections::HashMap, fmt::Display};
|
||||
use std::{collections::BTreeMap, fmt::Display};
|
||||
|
||||
use crate::{common::loc::LocBox, tokeniser::tokentype::*};
|
||||
use crate::{common::loc::LocBox, parser::ast::{Program, literal::Literal}, tokeniser::tokentype::*};
|
||||
|
||||
use super::{typ::Type, Ast};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub enum Expr {
|
||||
// Comment(Comment),
|
||||
Group(Box<LocBox<Expr>>),
|
||||
|
|
@ -58,7 +58,7 @@ pub enum Expr {
|
|||
If(IfExpr),
|
||||
Struct {
|
||||
path: Path,
|
||||
fields: HashMap<Ident, LocBox<Expr>>,
|
||||
fields: BTreeMap<Ident, LocBox<Expr>>,
|
||||
},
|
||||
Return(Box<Option<LocBox<Expr>>>),
|
||||
Break,
|
||||
|
|
@ -74,17 +74,30 @@ impl Expr {
|
|||
let Expr::Path(p) = self else {panic!("Unwrapping")};
|
||||
p.clone()
|
||||
}
|
||||
pub fn as_number(&self, prog: &Program) -> Option<Number> {
|
||||
match self {
|
||||
Self::Literal(Literal::Number(num)) => Some(*num),
|
||||
Self::Path(Path(path)) => {
|
||||
if let Some(val) = prog.get_const_var(path.last().unwrap()) {
|
||||
val.1.inner().val.inner().as_number(prog)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub struct CallParams(pub Vec<LocBox<Expr>>);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub struct Block(pub Vec<Ast>);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Hash)]
|
||||
pub struct Path(pub Vec<Ident>);
|
||||
|
||||
impl Display for Path {
|
||||
|
|
@ -100,14 +113,14 @@ impl Display for Path {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub struct IfExpr {
|
||||
pub test: Box<LocBox<Expr>>,
|
||||
pub body: Block,
|
||||
pub else_if: Option<IfBranchExpr>
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub enum IfBranchExpr {
|
||||
ElseIf(Box<IfExpr>),
|
||||
Else(Block)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use crate::{common::loc::LocBox, tokeniser::tokentype::*};
|
||||
use crate::{common::{Loc, loc::LocBox}, parser::ast::{Program, typ::Type}, tokeniser::tokentype::*, validator::{predefined::SIZE, validate_expr}};
|
||||
|
||||
use super::{expr::Expr, typ::Type, Ast};
|
||||
use super::expr::Expr;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub enum Literal {
|
||||
Number(Number),
|
||||
Ident(Ident),
|
||||
|
|
@ -13,6 +12,36 @@ pub enum Literal {
|
|||
Array(Vec<LocBox<Expr>>),
|
||||
ArrayRepeat {
|
||||
val: Box<LocBox<Expr>>,
|
||||
count: Box<LocBox<Expr>>,
|
||||
count: usize,
|
||||
},
|
||||
}
|
||||
|
||||
impl Literal {
|
||||
pub fn to_type(&self, prog: &mut Program) -> anyhow::Result<Type> {
|
||||
let t = match self {
|
||||
Self::Number(_) => Type::Builtin { name: String::from("usize"), size: SIZE as u8, signed: true },
|
||||
Self::Ident(ident) => Type::Owned(ident.clone()),
|
||||
Self::String(_) => Type::Owned(Ident(String::from("str"))),
|
||||
Self::Char(_) => Type::Owned(Ident(String::from("char"))),
|
||||
Self::Array(arr) => {
|
||||
if arr.is_empty() {
|
||||
Type::SizedArray {
|
||||
inner: Box::new(Type::Builtin { name: "void".to_string(), size: 0, signed: false }),
|
||||
count: LocBox::new(&Loc::default(), Expr::Literal(Literal::Number(Number { val: 0, base: 10, signed: false })))
|
||||
}
|
||||
} else {
|
||||
let item = arr.first().unwrap();
|
||||
Type::SizedArray {
|
||||
inner: Box::new(validate_expr(prog, item.inner())?.unwrap()),
|
||||
count: LocBox::new(item.loc(), Expr::Literal(Literal::Number(Number { val: arr.len(), base: 10, signed: false })))
|
||||
}
|
||||
}
|
||||
}
|
||||
Self::ArrayRepeat { val, count } => {
|
||||
Type::SizedArray { inner: Box::new(validate_expr(prog, val.inner())?.unwrap()), count: LocBox::new(val.loc(), Expr::Literal(Literal::Number(Number { val: *count, base: 10, signed: false })))}
|
||||
}
|
||||
|
||||
};
|
||||
Ok(t)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::collections::HashMap;
|
|||
|
||||
use statement::{ConstVar, Enum, Function, StaticVar, Struct};
|
||||
|
||||
use crate::{common::loc::LocBox, validator::predefined::TypeType};
|
||||
use crate::{common::loc::LocBox, parser::ast::{expr::Path, statement::Let, typ::Type}};
|
||||
pub use crate::tokeniser::tokentype::*;
|
||||
|
||||
pub mod expr;
|
||||
|
|
@ -10,19 +10,99 @@ pub mod literal;
|
|||
pub mod statement;
|
||||
pub mod typ;
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Scope {
|
||||
pub vars: HashMap<Ident, LocBox<Let>>,
|
||||
pub static_vars: HashMap<Ident, StaticVar>,
|
||||
pub const_vars: HashMap<Ident, ConstVar>,
|
||||
pub inner_scope: Option<Box<Scope>>
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Program {
|
||||
pub ast: expr::Block,
|
||||
pub structs: HashMap<Ident, LocBox<Struct>>,
|
||||
pub enums: HashMap<Ident, LocBox<Enum>>,
|
||||
pub types: HashMap<Ident, TypeType>,
|
||||
pub types: HashMap<Ident, LocBox<Type>>,
|
||||
pub functions: HashMap<Ident, LocBox<Function>>,
|
||||
pub member_functions: HashMap<Ident, HashMap<Ident, LocBox<Function>>>,
|
||||
pub static_vars: HashMap<Ident, StaticVar>,
|
||||
pub const_vars: HashMap<Ident, ConstVar>
|
||||
pub const_vars: HashMap<Ident, ConstVar>,
|
||||
pub scope: Option<Scope>
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
||||
impl Scope {
|
||||
pub fn get_var(&self, name: &Ident) -> Option<(Ident, LocBox<Let>)> {
|
||||
if let Some(inner) = &self.inner_scope {
|
||||
if let Some((ident, var)) = inner.get_var(name) {
|
||||
return Some((ident, var));
|
||||
}
|
||||
}
|
||||
if let Some(var) = self.vars.get(name) {
|
||||
return Some((name.clone(), var.clone()));
|
||||
}
|
||||
None
|
||||
}
|
||||
pub fn get_static_var(&self, name: &Ident) -> Option<(Ident, LocBox<StaticVar>)> {
|
||||
if let Some(inner) = &self.inner_scope {
|
||||
if let Some((ident, var)) = inner.get_static_var(name) {
|
||||
return Some((ident, var));
|
||||
}
|
||||
}
|
||||
if let Some(var) = self.static_vars.get(name) {
|
||||
return Some((name.clone(), LocBox::new(var.typ.loc(), var.clone())));
|
||||
}
|
||||
None
|
||||
}
|
||||
pub fn get_const_var(&self, name: &Ident) -> Option<(Ident, LocBox<ConstVar>)> {
|
||||
if let Some(inner) = &self.inner_scope {
|
||||
if let Some((ident, var)) = inner.get_const_var(name) {
|
||||
return Some((ident, var));
|
||||
}
|
||||
}
|
||||
if let Some(var) = self.const_vars.get(name) {
|
||||
return Some((name.clone(), LocBox::new(var.typ.loc(), var.clone())));
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Program {
|
||||
pub fn get_var(&self, name: &Ident) -> Option<(Ident, LocBox<Let>)> {
|
||||
if let Some(scope) = &self.scope {
|
||||
scope.get_var(name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn get_static_var(&self, name: &Ident) -> Option<(Ident, LocBox<StaticVar>)> {
|
||||
if let Some(scope) = &self.scope {
|
||||
if let Some((name, var)) = scope.get_static_var(name) {
|
||||
return Some((name, var));
|
||||
}
|
||||
}
|
||||
if let Some(var) = self.static_vars.get(name) {
|
||||
return Some((name.clone(), LocBox::new(var.typ.loc(), var.clone())));
|
||||
}
|
||||
None
|
||||
}
|
||||
pub fn get_const_var(&self, name: &Ident) -> Option<(Ident, LocBox<ConstVar>)> {
|
||||
if let Some(scope) = &self.scope {
|
||||
if let Some((name, var)) = scope.get_const_var(name) {
|
||||
return Some((name, var));
|
||||
}
|
||||
}
|
||||
if let Some(var) = self.const_vars.get(name) {
|
||||
return Some((name.clone(), LocBox::new(var.typ.loc(), var.clone())));
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub enum Ast {
|
||||
Expr(LocBox<expr::Expr>),
|
||||
Statement(LocBox<statement::Statement>),
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::bail;
|
||||
|
||||
use crate::{common::{loc::LocBox, Loc}, lerror};
|
||||
use crate::{common::loc::LocBox, lerror, parser::ast::expr::Path};
|
||||
|
||||
use super::{expr::{Block, Expr}, literal::Literal, typ::Type, Char, Ident, Number, Program, TString};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub enum Statement {
|
||||
Fn(Function),
|
||||
TypeAlias(TypeAlias),
|
||||
|
|
@ -15,46 +14,49 @@ pub enum Statement {
|
|||
Enum(Enum),
|
||||
ConstVar(ConstVar),
|
||||
StaticVar(StaticVar),
|
||||
Let {
|
||||
name: Ident,
|
||||
typ: Option<LocBox<Type>>,
|
||||
val: Option<LocBox<Expr>>,
|
||||
},
|
||||
Let(Let),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub struct Let {
|
||||
pub name: Ident,
|
||||
pub typ: Option<LocBox<Type>>,
|
||||
pub val: Option<LocBox<Expr>>,
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub struct ConstVar {
|
||||
pub name: Ident,
|
||||
pub typ: LocBox<Type>,
|
||||
pub val: LocBox<Expr>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub struct StaticVar {
|
||||
pub name: Ident,
|
||||
pub typ: LocBox<Type>,
|
||||
pub val: LocBox<Expr>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub struct TypeAlias {
|
||||
pub name: Ident,
|
||||
pub typ: LocBox<Type>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub struct Struct {
|
||||
pub name: Ident,
|
||||
pub fields: Vec<(Ident, LocBox<Type>)>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub struct Enum {
|
||||
pub name: Ident,
|
||||
pub fields: Vec<Ident>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub struct Function {
|
||||
pub struct_name: Option<Ident>,
|
||||
pub name: Ident,
|
||||
|
|
@ -123,7 +125,7 @@ impl Struct {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub enum ConstDataTyp {
|
||||
Byte(u8),
|
||||
AddrOfConst(Ident),
|
||||
|
|
@ -189,7 +191,18 @@ pub fn get_constant_data_as_bytes(program: &Program, value: LocBox<Expr>, is_lit
|
|||
bail!("")
|
||||
}
|
||||
let mut val = get_constant_data_as_bytes(program, (**val).clone(), is_little_endian, must_be_number)?;
|
||||
let num = get_constant_data_as_bytes(program, (**count).clone(), is_little_endian, true)?;
|
||||
|
||||
let mut num = Vec::new();
|
||||
let mut inc = 0;
|
||||
while inc < 8 {
|
||||
num.push(ConstDataTyp::Byte(((count << 8*inc) & 0xff) as u8));
|
||||
inc += 1;
|
||||
}
|
||||
|
||||
if is_little_endian {
|
||||
num.reverse();
|
||||
}
|
||||
|
||||
let mut count = 0 as usize;
|
||||
for b in num {
|
||||
let ConstDataTyp::Byte(b) = b else {unreachable!()};
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ use std::fmt::Display;
|
|||
|
||||
use anyhow::bail;
|
||||
|
||||
use crate::{common::{loc::LocBox, Loc}, logger::log, validator::predefined::TypeType};
|
||||
use crate::common::loc::LocBox;
|
||||
|
||||
use super::{expr::Expr, literal::Literal, Ident, Program};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub enum Type {
|
||||
Ref {
|
||||
inner: Box<Type>,
|
||||
|
|
@ -20,12 +20,84 @@ pub enum Type {
|
|||
inner: Box<Type>,
|
||||
},
|
||||
Owned(Ident),
|
||||
Builtin {
|
||||
name: String,
|
||||
size: u8,
|
||||
signed: bool,
|
||||
}
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn get_absolute_value(&self, program: &Program) -> anyhow::Result<Self> {
|
||||
match self {
|
||||
Self::Ref { inner, .. } => inner.get_absolute_value(program),
|
||||
Self::Owned(ident) => {
|
||||
if let Some(var) = program.get_var(ident) {
|
||||
Ok(var.1.inner().typ.clone().expect("type should be computed if were already using it").inner().clone())
|
||||
} else {
|
||||
bail!("");
|
||||
}
|
||||
}
|
||||
Self::SizedArray { .. } |
|
||||
Self::Builtin { .. } |
|
||||
Self::UnsizedArray { .. } => Ok(self.clone()),
|
||||
|
||||
}
|
||||
}
|
||||
pub fn is_numeric(&self, program: &Program) -> bool {
|
||||
match self {
|
||||
Self::Ref { inner, .. } => {
|
||||
inner.is_numeric(program)
|
||||
}
|
||||
Self::Owned(name) => {
|
||||
match program.types.get(&name) {
|
||||
Some(t) => t.inner().is_numeric(program),
|
||||
_ => false
|
||||
}
|
||||
},
|
||||
Self::SizedArray { .. } => false,
|
||||
Self::UnsizedArray { .. } => false,
|
||||
Self::Builtin { name, .. } => {
|
||||
match name.as_str() {
|
||||
"u8" | "i8" |
|
||||
"u16" | "i16" |
|
||||
"u32" | "i32" |
|
||||
"u64" | "i64" |
|
||||
"usize" | "isize" => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_ptr(&self, program: &Program) -> bool {
|
||||
match self {
|
||||
Self::Owned(name) => {
|
||||
match program.types.get(&name) {
|
||||
Some(t) => t.inner().is_ptr(program),
|
||||
_ => false
|
||||
}
|
||||
},
|
||||
Self::Ref { .. } => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_bool(&self, program: &Program) -> bool {
|
||||
match self {
|
||||
Self::Owned(name) => {
|
||||
match program.types.get(&name) {
|
||||
Some(t) => t.inner().is_bool(program),
|
||||
_ => false
|
||||
}
|
||||
},
|
||||
Self::Builtin { name, .. } if name.as_str() == "bool" => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
pub fn size_of(&self, program: &Program) -> anyhow::Result<usize> {
|
||||
match self {
|
||||
Self::Ref { inner, mutable } => {
|
||||
Self::Ref { .. } => {
|
||||
// TODO: Use the actual ptr size
|
||||
Ok(size_of::<*const ()>())
|
||||
}
|
||||
|
|
@ -35,20 +107,16 @@ impl Type {
|
|||
Self::SizedArray { inner, .. } => {
|
||||
Ok(inner.size_of(program)? )
|
||||
}
|
||||
Self::Builtin { size, .. } => {
|
||||
Ok(*size as usize)
|
||||
}
|
||||
Self::Owned(name) => {
|
||||
if let Some(v) = program.structs.get(&name) {
|
||||
return Ok(v.inner().get_size(program)?);
|
||||
}
|
||||
if let Some(v) = program.types.get(&name) {
|
||||
match v {
|
||||
TypeType::Normal(v) => {
|
||||
return Ok(v.inner().size_of(program)?);
|
||||
}
|
||||
TypeType::Builtin { size, .. } => {
|
||||
return Ok(*size);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(_) = program.enums.get(&name) {
|
||||
return Ok(4); // TODO: Make enum size changeable
|
||||
}
|
||||
|
|
@ -93,7 +161,10 @@ impl Display for Type {
|
|||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
Self::Owned(ident) => write!(f, "{ident}")
|
||||
Self::Owned(ident) => write!(f, "{ident}"),
|
||||
Self::Builtin { name, size, signed } => {
|
||||
write!(f, "(builtin) {} {}({})", name, if *signed { "signed" } else { "unsigned" }, size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
use std::collections::HashMap;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
|
||||
use crate::{common::loc::LocBox, debug, error, lerror, parser::{typ::parse_type, Punctuation}, tokeniser::Token};
|
||||
use crate::{common::loc::LocBox, debug, lerror, parser::{typ::parse_type, Punctuation}, tokeniser::Token};
|
||||
|
||||
use super::{ast::{expr::{Block, CallParams, Expr, IfBranchExpr, IfExpr, Path}, literal::Literal, TokenType}, parse_item, utils, Delimiter, Keyword};
|
||||
|
||||
|
|
@ -317,10 +317,15 @@ fn parse_literal(tokens: &mut Vec<Token>) -> Result<LocBox<Expr>> {
|
|||
bail!("")
|
||||
};
|
||||
let count = parse_expr(tokens, 0, false)?.unwrap();
|
||||
|
||||
let Expr::Literal(Literal::Number(count)) = count.inner() else {
|
||||
lerror!(count.loc(), "a repeating array accepts only literal numbers for count argument");
|
||||
bail!("")
|
||||
};
|
||||
utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::SquareR), "")?;
|
||||
return Ok(LocBox::new(start.loc(), Expr::Literal(Literal::ArrayRepeat {
|
||||
val: Box::new(typ),
|
||||
count: Box::new(count)
|
||||
count: count.val
|
||||
})));
|
||||
} else {
|
||||
if let Some(curr) = tokens.last() {
|
||||
|
|
@ -336,7 +341,7 @@ fn parse_literal(tokens: &mut Vec<Token>) -> Result<LocBox<Expr>> {
|
|||
|
||||
fn parse_struct_literal(tokens: &mut Vec<Token>, name: Path) -> Result<LocBox<Expr>> {
|
||||
let start = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::CurlyL), "")?;
|
||||
let mut fields = HashMap::new();
|
||||
let mut fields = BTreeMap::new();
|
||||
while !tokens.is_empty() {
|
||||
if let Some(_) = utils::check_consume(tokens, TokenType::Delim(Delimiter::CurlyR)) {
|
||||
break;
|
||||
|
|
@ -384,8 +389,8 @@ fn parse_path(tokens: &mut Vec<Token>) -> Result<LocBox<Expr>> {
|
|||
fn parse_unop(tokens: &mut Vec<Token>) -> Result<LocBox<Expr>> {
|
||||
let typ = utils::check_consume_or_err_from_many(tokens, &[
|
||||
TokenType::Punct(Punctuation::Not),
|
||||
TokenType::Punct(Punctuation::Plus),
|
||||
TokenType::Punct(Punctuation::Minus),
|
||||
TokenType::Punct(Punctuation::Plus), // Make number positive
|
||||
TokenType::Punct(Punctuation::Minus), // make number negative
|
||||
TokenType::Punct(Punctuation::Ampersand),
|
||||
TokenType::Punct(Punctuation::Star),
|
||||
], "")?;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@ pub fn parse_program(mut tokens: Vec<Token>) -> Result<Program> {
|
|||
types: HashMap::new(),
|
||||
structs: HashMap::new(),
|
||||
static_vars: HashMap::new(),
|
||||
const_vars: HashMap::new()
|
||||
const_vars: HashMap::new(),
|
||||
scope: None
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use anyhow::bail;
|
|||
use crate::common::loc::LocBox;
|
||||
use crate::lerror;
|
||||
use crate::parser::ast::TokenType;
|
||||
use crate::parser::ast::statement::Let;
|
||||
use crate::parser::expr::parse_expr;
|
||||
use crate::parser::{Delimiter, Ident, Keyword, Punctuation};
|
||||
use crate::tokeniser::Token;
|
||||
|
|
@ -121,7 +122,7 @@ fn parse_let(tokens: &mut Vec<Token>) -> Result<LocBox<Statement>> {
|
|||
val = Some(_val);
|
||||
}
|
||||
_ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), "")?;
|
||||
Ok(LocBox::new(kw.loc(), Statement::Let { name, typ, val }))
|
||||
Ok(LocBox::new(kw.loc(), Statement::Let(Let{ name, typ, val })))
|
||||
}
|
||||
fn parse_constant(tokens: &mut Vec<Token>) -> Result<LocBox<Statement>> {
|
||||
let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Const), "")?;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use anyhow::Result;
|
||||
use anyhow::{Result, bail};
|
||||
|
||||
use crate::{common::loc::LocBox, error, logger::log, parser::Delimiter, tokeniser::Token};
|
||||
use crate::{common::loc::LocBox, lerror, parser::{Delimiter, ast::{expr::Expr, literal::Literal}}, tokeniser::Token};
|
||||
|
||||
use super::{ast::{typ::Type, TokenType}, expr::parse_expr, utils, Keyword, Punctuation};
|
||||
|
||||
|
|
@ -26,9 +26,18 @@ pub fn parse_type(tokens: &mut Vec<Token>) -> Result<LocBox<Type>> {
|
|||
let itm_typ = parse_type(tokens)?;
|
||||
if let Some(_) = utils::check_consume(tokens, TokenType::Punct(Punctuation::Semi)) {
|
||||
let count = parse_expr(tokens, 0, false)?.unwrap();
|
||||
|
||||
match count.inner() {
|
||||
Expr::Literal(Literal::Number(_)) |
|
||||
Expr::Path(_) => (),
|
||||
_ => {
|
||||
lerror!(count.loc(), "Only literal numbers are allowed in sized arrays");
|
||||
bail!("")
|
||||
}
|
||||
}
|
||||
typ = Type::SizedArray {
|
||||
inner: Box::new(itm_typ.inner().clone()),
|
||||
count
|
||||
count: count
|
||||
};
|
||||
} else {
|
||||
typ = Type::UnsizedArray {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::{fs::File, path::{Path, PathBuf}};
|
|||
use crate::{cli::CliArgs, parser::ast::Program};
|
||||
|
||||
mod x86_64;
|
||||
mod none;
|
||||
//mod none;
|
||||
|
||||
pub fn get_default_target() -> String {
|
||||
x86_64::cgen::linux::CGen::get_target_triple().to_string()
|
||||
|
|
@ -13,7 +13,7 @@ pub fn get_all_targets() -> Vec<&'static str> {
|
|||
// x86_64::asmgen::linux::AsmGen::get_target_triple(),
|
||||
// x86_64::cgen::linux::CGen::get_target_triple(),
|
||||
// x86_64::llvmgen::linux::LlvmGen::get_target_triple(),
|
||||
none::luagen::cct::LuaGen::get_target_triple(),
|
||||
//none::luagen::cct::LuaGen::get_target_triple(),
|
||||
x86_64::cgen::linux::CGen::get_target_triple(),
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::{fs::File, ops::Deref};
|
||||
use std::io::Write;
|
||||
use crate::{common::Loc, parser::ast::{expr::Expr, literal::Literal, statement::{Function, Statement, Struct}, typ::Type, Ast, Ident, Program, Punctuation}, targets::Target, validator::predefined::TypeType};
|
||||
use crate::{common::Loc, parser::ast::{expr::Expr, literal::Literal, statement::{Function, Statement, Struct}, typ::Type, Ast, Ident, Program, Punctuation}, targets::Target};
|
||||
|
||||
const INTERNAL_CODE: &'static str = include_str!("internals.c");
|
||||
|
||||
|
|
@ -19,8 +19,8 @@ impl Target for CGen {
|
|||
fn write_code(&mut self, program: &crate::parser::ast::Program, f: &mut File) -> anyhow::Result<()> {
|
||||
self.write_fat_comment(f, "Internal number types");
|
||||
for (name, typ) in &program.types {
|
||||
if let TypeType::Builtin { size: _, signed: _ } = typ {
|
||||
self.write_internal_type(f, program, name, typ)?;
|
||||
if let Type::Builtin { name: _, size: _, signed: _ } = typ.inner() {
|
||||
self.write_internal_type(f, program, name, typ.inner())?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -34,9 +34,7 @@ impl Target for CGen {
|
|||
|
||||
self.write_fat_comment(f, "Type aliases");
|
||||
for (name, typ) in &program.types {
|
||||
if let TypeType::Normal(t) = typ {
|
||||
self.write_typedef(f, program, t.inner(), name)?;
|
||||
}
|
||||
self.write_typedef(f, program, typ.inner(), name)?;
|
||||
}
|
||||
|
||||
self.write_fat_comment(f, "Struct definitions");
|
||||
|
|
@ -45,7 +43,7 @@ impl Target for CGen {
|
|||
}
|
||||
|
||||
self.write_fat_comment(f, "Function forward declarations");
|
||||
fn write_fn_fwdclr(slf: &mut CGen, program: &Program, f: &mut File, name: &Ident, func: &Function) -> anyhow::Result<()> {
|
||||
fn write_fn_fwdclr(slf: &mut CGen, program: &Program, f: &mut File, _name: &Ident, func: &Function) -> anyhow::Result<()> {
|
||||
writeln!(f, "// {}", func.get_def_as_str())?;
|
||||
if let Some(rett) = &func.ret_type {
|
||||
slf.write_type(f, program, rett.inner())?;
|
||||
|
|
@ -121,7 +119,7 @@ impl CGen {
|
|||
Expr::If(_ifexpr) => {
|
||||
|
||||
}
|
||||
Expr::BinOp { typ, left, right } => {
|
||||
Expr::BinOp { typ, .. } => {
|
||||
match typ {
|
||||
Punctuation::Eq => {
|
||||
|
||||
|
|
@ -182,6 +180,7 @@ impl CGen {
|
|||
pf.push_str(&part(f, program, inner)?);
|
||||
pf.push_str("[]");
|
||||
}
|
||||
Type::Builtin { .. } => ()
|
||||
}
|
||||
Ok(pf)
|
||||
}
|
||||
|
|
@ -223,14 +222,14 @@ impl CGen {
|
|||
write!(f, "[]")?;
|
||||
}
|
||||
}
|
||||
Type::Builtin { .. } => ()
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_internal_type(&mut self, f: &mut File, program: &Program, name: &Ident, typ: &TypeType) -> anyhow::Result<()> {
|
||||
fn write_internal_type(&mut self, f: &mut File, _program: &Program, _name: &Ident, typ: &Type) -> anyhow::Result<()> {
|
||||
match typ {
|
||||
TypeType::Normal(typ) => unreachable!(),
|
||||
TypeType::Builtin{ size, signed } => {
|
||||
Type::Builtin{ name, size, signed } => {
|
||||
if *size == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
|
@ -249,7 +248,7 @@ impl CGen {
|
|||
8 => write!(f, "long long ")?,
|
||||
3 | 5 | 6 | 7 => unreachable!(),
|
||||
}
|
||||
writeln!(f, "{};", name.0)?;
|
||||
writeln!(f, "{};", name)?;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
|
@ -267,7 +266,7 @@ impl CGen {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn write_fn(&mut self, f: &mut File, program: &Program, func: &Function, loc: &Loc) -> anyhow::Result<()> {
|
||||
fn write_fn(&mut self, f: &mut File, program: &Program, func: &Function, _loc: &Loc) -> anyhow::Result<()> {
|
||||
writeln!(f, "\n\n// {}", func.get_def_as_str())?;
|
||||
if let Some(rett) = &func.ret_type {
|
||||
self.write_type(f, program, rett.inner())?;
|
||||
|
|
@ -295,7 +294,7 @@ impl CGen {
|
|||
Ast::Expr(expr) => {
|
||||
self.write_expr(f, program, expr.inner(), expr.loc())?
|
||||
}
|
||||
Ast::Statement(stat) => {
|
||||
Ast::Statement(_) => {
|
||||
//todo!()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::{collections::HashMap, fmt::Display};
|
||||
use anyhow::bail;
|
||||
use parse_int::parse;
|
||||
use crate::{common::{loc::LocIncr, Loc}, error, lerror};
|
||||
use crate::{common::{loc::LocIncr, Loc},lerror};
|
||||
|
||||
pub mod tokentype;
|
||||
use tokentype::*;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
use core::panic;
|
||||
use std::fmt::Display;
|
||||
|
||||
use crate::parser::ast::expr::Path;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Ident(pub String);
|
||||
|
||||
|
|
@ -10,6 +12,12 @@ impl Display for Ident {
|
|||
}
|
||||
}
|
||||
|
||||
impl Ident {
|
||||
pub fn as_path(self) -> Path {
|
||||
Path(vec![self])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Number {
|
||||
|
|
|
|||
59
src/validator/calculate_types.rs
Normal file
59
src/validator/calculate_types.rs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
use anyhow::bail;
|
||||
|
||||
use crate::{common::loc::LocBox, parser::ast::{Ast, Program, expr::Expr, statement::Statement}, validator::validate_expr};
|
||||
|
||||
|
||||
|
||||
|
||||
pub fn calc(prog: &mut Program) -> anyhow::Result<()> {
|
||||
let mut body = prog.ast.0.clone();
|
||||
for item in body.iter_mut() {
|
||||
calc_ast(prog, item)?;
|
||||
}
|
||||
prog.ast.0 = body;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn calc_ast(prog: &mut Program, ast: &mut Ast) -> anyhow::Result<()> {
|
||||
match ast {
|
||||
Ast::Statement(ref mut stat) => calc_stat(prog, stat.inner_mut())?,
|
||||
Ast::Expr(ref mut 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,14 +1,11 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::{anyhow, bail};
|
||||
use anyhow::bail;
|
||||
|
||||
use crate::{common::{loc::LocBox, Loc}, parser::ast::{expr::{Block, Expr}, statement::{Statement, TypeAlias}, typ::Type, Ast, Program}};
|
||||
use crate::{common::{Loc, loc::LocBox}, parser::ast::{Ast, Program, Punctuation, TokenType, expr::*, statement::*, typ::Type}};
|
||||
|
||||
pub mod predefined;
|
||||
|
||||
struct Scope {
|
||||
|
||||
}
|
||||
pub mod calculate_types;
|
||||
|
||||
pub fn validate_code(prog: &mut Program) -> anyhow::Result<()> {
|
||||
let Block(items) = prog.ast.clone();
|
||||
|
|
@ -20,24 +17,9 @@ pub fn validate_code(prog: &mut Program) -> anyhow::Result<()> {
|
|||
//dbg!(&prog.enums);
|
||||
//dbg!(&prog.member_functions);
|
||||
//dbg!(&prog.functions);
|
||||
for item in items {
|
||||
for item in items.iter() {
|
||||
match item {
|
||||
Ast::Statement(stat) => {
|
||||
match stat.inner() {
|
||||
Statement::Fn(func) => {}
|
||||
Statement::Let { .. } => {
|
||||
lerror!(stat.loc(), "Let statements are not allowed outside a function");
|
||||
bail!("")
|
||||
}
|
||||
Statement::ConstVar(var) => {
|
||||
}
|
||||
Statement::StaticVar(var) => {
|
||||
}
|
||||
Statement::Enum(enm) => {}
|
||||
Statement::Struct(strct) => {}
|
||||
Statement::TypeAlias(alias) => {}
|
||||
}
|
||||
}
|
||||
Ast::Statement(ref stat) => validate_stat(prog, &stat, CurrentState::Outside)?,
|
||||
Ast::Expr(_) => unreachable!()
|
||||
}
|
||||
}
|
||||
|
|
@ -46,6 +28,406 @@ pub fn validate_code(prog: &mut Program) -> anyhow::Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
enum CurrentState {
|
||||
InFunc,
|
||||
Outside,
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn validate_stat(prog: &mut Program, stat: &LocBox<Statement>, current_state: CurrentState) -> anyhow::Result<()> {
|
||||
match stat.inner() {
|
||||
Statement::Fn(func) => validate_fn(prog, &func)?,
|
||||
Statement::Let(lt) if current_state == CurrentState::InFunc => validate_stat_let(prog, lt)?,
|
||||
Statement::Let(_) if current_state == CurrentState::Outside => {
|
||||
lerror!(stat.loc(), "Let statements are not allowed outside a function");
|
||||
bail!("")
|
||||
}
|
||||
Statement::ConstVar(var) => validate_const_var(prog, var)?,
|
||||
Statement::StaticVar(var) => validate_static_var(prog, var)?,
|
||||
Statement::Enum(enm) => validate_enum(prog, enm)?,
|
||||
Statement::Struct(strct) => validate_struct(prog, strct)?,
|
||||
Statement::TypeAlias(alias) => validate_type_alias(prog, alias)?,
|
||||
Statement::Let(_) => unreachable!()
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_stat_let(prog: &mut Program, lt: &Let) -> anyhow::Result<()> {
|
||||
if let Some(val) = <.val && let Some(t) = <.typ {
|
||||
let typ = validate_expr(prog, &val.inner())?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_ast(prog: &mut Program, ast: &Ast) -> anyhow::Result<Option<Type>> {
|
||||
match ast {
|
||||
Ast::Expr(expr) => {
|
||||
validate_expr(prog, &expr.inner())
|
||||
}
|
||||
Ast::Statement(stat) => {
|
||||
validate_stat(prog, &stat, CurrentState::InFunc)?;
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn validate_expr(prog: &mut Program, expr: &Expr) -> anyhow::Result<Option<Type>> {
|
||||
match expr {
|
||||
Expr::Break | Expr::Continue => Ok(None),
|
||||
Expr::Return(ref ret) => {
|
||||
if let Some(expr) = &**ret {
|
||||
validate_expr(prog, expr.inner())
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
Expr::Struct { path, fields } => {
|
||||
// this is probably fucked so fix this later
|
||||
let name = path.0.last().expect("Paths always have at least one part");
|
||||
let typ = Type::Owned(name.clone());
|
||||
// this is so ass, this checks if struct exists
|
||||
validate_type(prog, &LocBox::new(&Loc::default(), typ.clone()))?;
|
||||
|
||||
for field in fields {
|
||||
validate_expr(prog, &field.1.inner())?;
|
||||
}
|
||||
|
||||
Ok(Some(typ))
|
||||
},
|
||||
Expr::If(ifs) => {
|
||||
validate_expr(prog, ifs.test.inner())?;
|
||||
for item in &ifs.body.0 {
|
||||
validate_ast(prog, item)?;
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
Expr::Path(path) => {
|
||||
// TODO: Path hell TBD
|
||||
Ok(Some(Type::Owned(path.0.last().unwrap().clone())))
|
||||
}
|
||||
Expr::Group(group) => validate_expr(prog, &group.inner()),
|
||||
Expr::Call { path, params } => {
|
||||
let loc = path.loc();
|
||||
let Expr::Path(path) = path.inner() else {
|
||||
panic!("fml");
|
||||
};
|
||||
|
||||
let func;
|
||||
match path.0.len() {
|
||||
1 => {
|
||||
let f = prog.functions.get(&path.0[0]);
|
||||
match f {
|
||||
Some(f) => func = f.clone(),
|
||||
None => {
|
||||
lerror!(loc, "Could not find function {}", path);
|
||||
panic!("")
|
||||
}
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
let s = prog.member_functions.get(&path.0[0]).unwrap();
|
||||
let f = s.get(&path.0[1]);
|
||||
match f {
|
||||
Some(f) => func = LocBox::new(loc, f.clone().inner().clone()),
|
||||
None => {
|
||||
lerror!(loc, "Could not find function {}", path);
|
||||
panic!("")
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => panic!("")
|
||||
}
|
||||
|
||||
|
||||
for (i, param) in params.0.iter().enumerate() {
|
||||
let t = validate_expr(prog, param.inner())?;
|
||||
let ft = func.inner().params[i].1.inner();
|
||||
if t.as_ref() != Some(ft) {
|
||||
lerror!(param.loc(), "expected {ft}, got {}", t.unwrap());
|
||||
bail!("")
|
||||
}
|
||||
}
|
||||
if let Some(t) = &func.inner().ret_type {
|
||||
Ok(Some(t.inner().clone()))
|
||||
} else {
|
||||
Ok(None)
|
||||
|
||||
}
|
||||
}
|
||||
Expr::ForLoop { init, test, on_loop, body } => {
|
||||
let _ = validate_ast(prog, init)?;
|
||||
let _ = validate_expr(prog, test.inner())?;
|
||||
let _ = validate_expr(prog, on_loop.inner())?;
|
||||
for item in &body.0 {
|
||||
let _ = validate_ast(prog, item)?;
|
||||
}
|
||||
Ok(None)
|
||||
},
|
||||
Expr::Cast { left, right } => {
|
||||
validate_expr(prog, left.inner())?;
|
||||
Ok(Some(right.inner().clone()))
|
||||
}
|
||||
Expr::Literal(lit) => {
|
||||
Ok(Some(lit.to_type(prog)?))
|
||||
}
|
||||
Expr::UnOp { typ, right } => {
|
||||
match typ {
|
||||
Punctuation::Not => {
|
||||
let t = validate_expr(prog, right.inner())?.unwrap();
|
||||
if !t.is_bool(prog) {
|
||||
lerror!(right.loc(), "Expected bool, got {t}");
|
||||
}
|
||||
Ok(Some(t))
|
||||
}
|
||||
Punctuation::Minus |
|
||||
Punctuation::Plus => {
|
||||
let t = validate_expr(prog, right.inner())?.unwrap();
|
||||
if !t.is_numeric(prog) {
|
||||
lerror!(right.loc(), "Expected number, got {t}");
|
||||
}
|
||||
Ok(Some(t))
|
||||
}
|
||||
|
||||
Punctuation::Ampersand => {
|
||||
let t = validate_expr(prog, right.inner())?.unwrap();
|
||||
Ok(Some(Type::Ref { inner: Box::new(t), mutable: false }))
|
||||
}
|
||||
Punctuation::Star => {
|
||||
let t = validate_expr(prog, right.inner())?.unwrap();
|
||||
if !t.is_ptr(prog) {
|
||||
lerror!(right.loc(), "Expected pointer, got {t}");
|
||||
}
|
||||
|
||||
match t {
|
||||
Type::Ref { inner, .. } => Ok(Some(*inner)),
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
_ => unreachable!()
|
||||
}
|
||||
},
|
||||
Expr::BinOp { typ, left, right } => {
|
||||
match typ {
|
||||
Punctuation::Ampersand |
|
||||
Punctuation::Or |
|
||||
Punctuation::Xor |
|
||||
Punctuation::Plus |
|
||||
Punctuation::Minus |
|
||||
Punctuation::Div |
|
||||
Punctuation::Star |
|
||||
Punctuation::Mod |
|
||||
Punctuation::Shl |
|
||||
Punctuation::Shr => {
|
||||
let t1_s;
|
||||
let t2_s;
|
||||
let t1 = validate_expr(prog, left.inner())?.unwrap();
|
||||
let t2 = validate_expr(prog, right.inner())?.unwrap();
|
||||
if !t1.is_numeric(prog) {
|
||||
lerror!(right.loc(), "Expected bool, got {t1}");
|
||||
}
|
||||
if !t2.is_numeric(prog) {
|
||||
lerror!(right.loc(), "Expected bool, got {t2}");
|
||||
}
|
||||
match &t1 {
|
||||
Type::Builtin { name: _, size, .. } => t1_s = *size,
|
||||
_ => unreachable!()
|
||||
}
|
||||
|
||||
match &t2 {
|
||||
Type::Builtin { name: _, size, .. } => t2_s = *size,
|
||||
_ => unreachable!()
|
||||
}
|
||||
if t2_s > t1_s {
|
||||
Ok(Some(t2))
|
||||
} else {
|
||||
Ok(Some(t1))
|
||||
}
|
||||
}
|
||||
Punctuation::EqEq |
|
||||
Punctuation::Lt |
|
||||
Punctuation::Gt |
|
||||
Punctuation::Le |
|
||||
Punctuation::Ge |
|
||||
Punctuation::AndAnd |
|
||||
Punctuation::OrOr => {
|
||||
let t1 = validate_expr(prog, left.inner())?.unwrap();
|
||||
let t2 = validate_expr(prog, right.inner())?.unwrap();
|
||||
if !t1.is_bool(prog) {
|
||||
lerror!(right.loc(), "Expected bool, got {t1}");
|
||||
}
|
||||
if !t2.is_bool(prog) {
|
||||
lerror!(right.loc(), "Expected bool, got {t2}");
|
||||
}
|
||||
Ok(Some(t1))
|
||||
}
|
||||
|
||||
Punctuation::AddEq |
|
||||
Punctuation::SubEq |
|
||||
Punctuation::DivEq |
|
||||
Punctuation::MulEq |
|
||||
Punctuation::ModEq |
|
||||
Punctuation::ShlEq |
|
||||
Punctuation::ShrEq |
|
||||
Punctuation::AndEq |
|
||||
Punctuation::OrEq |
|
||||
Punctuation::XorEq => {
|
||||
let var = validate_expr(prog, left.inner())?.unwrap();
|
||||
let var_t = var.get_absolute_value(prog)?;
|
||||
let val_t = validate_expr(prog, right.inner())?.unwrap();
|
||||
|
||||
if !(var_t.is_numeric(prog) && val_t.is_numeric(prog)) {
|
||||
lerror!(left.loc(), "Mismatched types, assigning {val_t} to {var_t}");
|
||||
bail!("");
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
Punctuation::Eq => {
|
||||
let var = validate_expr(prog, left.inner())?.unwrap();
|
||||
let var_t = var.get_absolute_value(prog)?;
|
||||
let val_t = validate_expr(prog, right.inner())?.unwrap();
|
||||
|
||||
if !(var_t == val_t || var_t.is_numeric(prog) && val_t.is_numeric(prog)) {
|
||||
lerror!(left.loc(), "Mismatched types, assigning {val_t} to {var_t}");
|
||||
bail!("");
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
_ => unreachable!()
|
||||
}
|
||||
},
|
||||
Expr::ArrayIndex { name, index } => {
|
||||
let left = validate_expr(prog, name.inner())?;
|
||||
let Some(left) = left else {
|
||||
lerror!(name.loc(), "expected value, got nothing, cannot index nothing");
|
||||
bail!("")
|
||||
};
|
||||
fn f(prog: &mut Program, left: &Type, loc: &Loc, index: &LocBox<Expr>) -> anyhow::Result<Option<Type>> {
|
||||
match left {
|
||||
Type::SizedArray { inner, count } => {
|
||||
let val1 = count.inner().as_number(prog).unwrap();
|
||||
let val2 = index.inner().as_number(prog).unwrap();
|
||||
if val1.signed && (val1.val as isize) < 0 {
|
||||
lerror!(index.loc(), "Cannot index bellow 0");
|
||||
bail!("");
|
||||
}
|
||||
|
||||
if val1.val <= val2.val {
|
||||
lerror!(index.loc(), "Cannot index outside aray boundaries");
|
||||
bail!("");
|
||||
}
|
||||
Ok(Some(*inner.clone()))
|
||||
}
|
||||
Type::UnsizedArray { inner } => {
|
||||
Ok(Some(*inner.clone()))
|
||||
}
|
||||
Type::Owned(name) => {
|
||||
let t = prog.types.get(name).cloned();
|
||||
if let Some(t) = t {
|
||||
f(prog, t.inner(), t.loc(), index)
|
||||
} else {
|
||||
lerror!(loc, "Unknown type {name}");
|
||||
bail!("")
|
||||
}
|
||||
}
|
||||
Type::Ref { .. } |
|
||||
Type::Builtin { .. } => {
|
||||
lerror!(loc, "Numeric, pointer, and void types are not indexable (TODO: Maybe allow indexing pointers?)");
|
||||
bail!("")
|
||||
}
|
||||
}
|
||||
}
|
||||
f(prog, &left, name.loc(), &index)
|
||||
},
|
||||
Expr::PtrFieldAccess { left, right } |
|
||||
Expr::FieldAccess { left, right } => {
|
||||
let left = validate_expr(prog, left.clone().unwrap().inner())?;
|
||||
let right = validate_expr(prog, right.clone().inner())?.unwrap();
|
||||
let Type::Owned(right) = right else {
|
||||
panic!()
|
||||
};
|
||||
match left.unwrap() {
|
||||
Type::Owned(name) => {
|
||||
if let Some(strct) = prog.structs.get(&name) {
|
||||
for field in &strct.inner().fields {
|
||||
if field.0 == right {
|
||||
return Ok(Some(field.1.inner().clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => panic!()
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
},
|
||||
Expr::WhileLoop { test, body } => {
|
||||
let _ = validate_expr(prog, test.inner())?;
|
||||
for item in &body.0 {
|
||||
let _ = validate_ast(prog, item)?;
|
||||
}
|
||||
Ok(None)
|
||||
|
||||
},
|
||||
Expr::InfLoop { body } => {
|
||||
for item in &body.0 {
|
||||
let _ = validate_ast(prog, item)?;
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_fn(prog: &mut Program, func: &Function) -> anyhow::Result<()> {
|
||||
for param in &func.params {
|
||||
validate_type(prog, ¶m.1)?;
|
||||
}
|
||||
if let Some(body) = &func.body {
|
||||
for item in &body.0 {
|
||||
validate_ast(prog, item)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_const_var(prog: &mut Program, var: &ConstVar) -> anyhow::Result<()> {
|
||||
validate_type(prog, &var.typ)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_static_var(prog: &mut Program, var: &StaticVar) -> anyhow::Result<()> {
|
||||
validate_type(prog, &var.typ)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_enum(_: &mut Program, _: &Enum) -> anyhow::Result<()> {
|
||||
// Enum has no actual types
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_struct(prog: &mut Program, strct: &Struct) -> anyhow::Result<()> {
|
||||
for field in &strct.fields {
|
||||
if let Err(e) = validate_type(prog, &field.1) {
|
||||
error!("Could not find type in field {}::{}", strct.name, field.0);
|
||||
anyhow::bail!(e);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_type_alias(prog: &mut Program, alias: &TypeAlias) -> anyhow::Result<()> {
|
||||
validate_type(prog, &alias.typ)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
fn check_that_types_exist_for_items(prog: &mut Program, items: &Vec<Ast>) -> anyhow::Result<()> {
|
||||
let mut errored = false;
|
||||
for item in items {
|
||||
|
|
@ -116,10 +498,11 @@ fn validate_type(prog: &mut Program, typ: &LocBox<Type>) -> anyhow::Result<()> {
|
|||
prog.structs.get(typ).is_some() {
|
||||
Ok(())
|
||||
} else {
|
||||
// lerror!(loc, "Could not find type '{}'", typ.0);
|
||||
lerror!(loc, "Could not find type '{}'", typ.0);
|
||||
bail!("")
|
||||
}
|
||||
}
|
||||
Type::Builtin { .. } => Ok(())
|
||||
}
|
||||
}
|
||||
f(prog, typ.inner(), typ.loc())
|
||||
|
|
@ -153,7 +536,7 @@ fn collect_types_and_constants(prog: &mut Program, items: &Vec<Ast>) {
|
|||
}
|
||||
Statement::TypeAlias(alias) => {
|
||||
let typ = alias.clone().typ.inner().clone();
|
||||
prog.types.insert(alias.name.clone(), predefined::TypeType::Normal(LocBox::new(stat.loc(), typ)));
|
||||
prog.types.insert(alias.name.clone(), LocBox::new(stat.loc(), typ));
|
||||
}
|
||||
Statement::Let { .. } => (),
|
||||
Statement::ConstVar(var) => {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
use std::collections::HashMap;
|
||||
use lazy_static::lazy_static;
|
||||
use crate::common::Loc;
|
||||
use crate::parser::ast::expr::Path;
|
||||
use crate::parser::typ::parse_type;
|
||||
use crate::{common::loc::LocBox, parser::ast::{statement::Function, typ::Type, Ident, Program}};
|
||||
|
||||
#[cfg(target_arch="x86_64")]
|
||||
const SIZE: usize = 8;
|
||||
pub const SIZE: usize = 8;
|
||||
#[cfg(target_arch="x86")]
|
||||
const SIZE: usize = 4;
|
||||
pub const SIZE: usize = 4;
|
||||
|
||||
lazy_static!(
|
||||
pub static ref TYPES_RAW: HashMap<&'static str, (usize, bool)> = [
|
||||
|
|
@ -22,6 +23,7 @@ lazy_static!(
|
|||
("i16", (2, true)),
|
||||
("i32", (4, true)),
|
||||
("i64", (8, true)),
|
||||
("bool", (1, true)),
|
||||
].into();
|
||||
pub static ref FUNCTIONS: HashMap<&'static str, (Vec<(&'static str, &'static str)>, &'static str)> = [
|
||||
("syscall", (vec![
|
||||
|
|
@ -32,18 +34,14 @@ lazy_static!(
|
|||
].into();
|
||||
);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum TypeType {
|
||||
Normal(LocBox<Type>),
|
||||
Builtin {
|
||||
size: usize,
|
||||
signed: bool,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_builtin(prog: &mut Program) {
|
||||
let loc = Loc::new("(internal)", 0, 0);
|
||||
for (name, (size, signed)) in TYPES_RAW.iter() {
|
||||
prog.types.insert(Ident(name.to_string()), TypeType::Builtin{ size: *size, signed: *signed });
|
||||
prog.types.insert(
|
||||
Ident(name.to_string()),
|
||||
LocBox::new(&loc, Type::Builtin{ name: name.to_string(), size: *size as u8, signed: *signed })
|
||||
);
|
||||
}
|
||||
|
||||
for (name, (args, ret_typ)) in FUNCTIONS.iter() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user