diff --git a/include/std.mcl b/include/std.mcl deleted file mode 100644 index ffb1822..0000000 --- a/include/std.mcl +++ /dev/null @@ -1,7 +0,0 @@ - - -// fn syscall(arg_count: usize, syscall_num: usize, args: ) - -fn puts(s: &str) { - __INTERNAL_syscall(1 as u8, 1 as u8, &[s] as &[&void]); -} diff --git a/libbeaker.a b/libbeaker.a new file mode 100644 index 0000000..4d6d094 Binary files /dev/null and b/libbeaker.a differ diff --git a/tests/parser/enumerations.exp b/old_tests/parser/enumerations.exp similarity index 100% rename from tests/parser/enumerations.exp rename to old_tests/parser/enumerations.exp diff --git a/tests/parser/enumerations.mcl b/old_tests/parser/enumerations.mcl similarity index 100% rename from tests/parser/enumerations.mcl rename to old_tests/parser/enumerations.mcl diff --git a/tests/parser/expressions.exp b/old_tests/parser/expressions.exp similarity index 100% rename from tests/parser/expressions.exp rename to old_tests/parser/expressions.exp diff --git a/tests/parser/expressions.mcl b/old_tests/parser/expressions.mcl similarity index 100% rename from tests/parser/expressions.mcl rename to old_tests/parser/expressions.mcl diff --git a/tests/parser/functions.exp b/old_tests/parser/functions.exp similarity index 100% rename from tests/parser/functions.exp rename to old_tests/parser/functions.exp diff --git a/tests/parser/functions.mcl b/old_tests/parser/functions.mcl similarity index 100% rename from tests/parser/functions.mcl rename to old_tests/parser/functions.mcl diff --git a/tests/parser/if-statements.exp b/old_tests/parser/if-statements.exp similarity index 100% rename from tests/parser/if-statements.exp rename to old_tests/parser/if-statements.exp diff --git a/tests/parser/if-statements.mcl b/old_tests/parser/if-statements.mcl similarity index 100% rename from tests/parser/if-statements.mcl rename to old_tests/parser/if-statements.mcl diff --git a/tests/parser/loops.exp b/old_tests/parser/loops.exp similarity index 100% rename from tests/parser/loops.exp rename to old_tests/parser/loops.exp diff --git a/tests/parser/loops.mcl b/old_tests/parser/loops.mcl similarity index 100% rename from tests/parser/loops.mcl rename to old_tests/parser/loops.mcl diff --git a/tests/parser/structs.exp b/old_tests/parser/structs.exp similarity index 100% rename from tests/parser/structs.exp rename to old_tests/parser/structs.exp diff --git a/tests/parser/structs.mcl b/old_tests/parser/structs.mcl similarity index 100% rename from tests/parser/structs.mcl rename to old_tests/parser/structs.mcl diff --git a/old_tests/tokeniser/comments.exp b/old_tests/tokeniser/comments.exp new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/old_tests/tokeniser/comments.exp @@ -0,0 +1 @@ +[] diff --git a/tests/tokeniser/comments.mcl b/old_tests/tokeniser/comments.mcl similarity index 100% rename from tests/tokeniser/comments.mcl rename to old_tests/tokeniser/comments.mcl diff --git a/tests/tokeniser/delimiters.exp b/old_tests/tokeniser/delimiters.exp similarity index 99% rename from tests/tokeniser/delimiters.exp rename to old_tests/tokeniser/delimiters.exp index 1310a98..5a34a42 100644 --- a/tests/tokeniser/delimiters.exp +++ b/old_tests/tokeniser/delimiters.exp @@ -59,4 +59,4 @@ SquareL, ), }, -] \ No newline at end of file +] diff --git a/tests/tokeniser/delimiters.mcl b/old_tests/tokeniser/delimiters.mcl similarity index 100% rename from tests/tokeniser/delimiters.mcl rename to old_tests/tokeniser/delimiters.mcl diff --git a/tests/tokeniser/keywords.exp b/old_tests/tokeniser/keywords.exp similarity index 100% rename from tests/tokeniser/keywords.exp rename to old_tests/tokeniser/keywords.exp diff --git a/tests/tokeniser/keywords.mcl b/old_tests/tokeniser/keywords.mcl similarity index 100% rename from tests/tokeniser/keywords.mcl rename to old_tests/tokeniser/keywords.mcl diff --git a/tests/tokeniser/literals.exp b/old_tests/tokeniser/literals.exp similarity index 100% rename from tests/tokeniser/literals.exp rename to old_tests/tokeniser/literals.exp diff --git a/tests/tokeniser/literals.mcl b/old_tests/tokeniser/literals.mcl similarity index 100% rename from tests/tokeniser/literals.mcl rename to old_tests/tokeniser/literals.mcl diff --git a/tests/tokeniser/punctuation.exp b/old_tests/tokeniser/punctuation.exp similarity index 100% rename from tests/tokeniser/punctuation.exp rename to old_tests/tokeniser/punctuation.exp diff --git a/tests/tokeniser/punctuation.mcl b/old_tests/tokeniser/punctuation.mcl similarity index 100% rename from tests/tokeniser/punctuation.mcl rename to old_tests/tokeniser/punctuation.mcl diff --git a/src/bin/test/logger.rs b/src/bin/tester/logger.rs similarity index 100% rename from src/bin/test/logger.rs rename to src/bin/tester/logger.rs diff --git a/src/bin/test/main.rs b/src/bin/tester/main.rs similarity index 98% rename from src/bin/test/main.rs rename to src/bin/tester/main.rs index d782a93..fd5df70 100644 --- a/src/bin/test/main.rs +++ b/src/bin/tester/main.rs @@ -133,7 +133,7 @@ fn test_parser(cf: &CollectedFiles, compile: bool) -> anyhow::Result { continue; } }; - let ast = match mclangc::parser::parse_program(tokens) { + let ast = match mclangc::parser::parse_program(tokens, &mclangc::cli::CliArgs::default()) { Ok(v) => v, Err(e) => { crate::error!("Test parser/{name} had an error: {e}"); diff --git a/src/cli.rs b/src/cli.rs index d7a2146..382b955 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -13,11 +13,16 @@ pub struct CliArgs { quiet: bool, #[arg(long, short, value_parser=crate::targets::get_all_targets(), default_value_t=crate::targets::get_default_target())] pub target: String, - #[arg(long="include", short='I', default_values=["include"])] + #[arg(long="include", short='I', default_values=[".", "include"])] pub include_paths: Vec, /// Output file #[arg(long, short, default_value="a.out")] pub output: String, + + /// Linker args + #[arg(long, short='L')] + pub linker_args: Vec, + /// All input files #[clap(num_args = 1..)] pub input: Vec diff --git a/src/main.rs b/src/main.rs index c7cc397..46325e0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,6 @@ mod logger; - fn main() -> anyhow::Result<()> { let cli = mclangc::cli::CliArgs::parse(); cli.set_log_level(); @@ -25,9 +24,12 @@ fn main() -> anyhow::Result<()> { // dbg!(&tokens); info!("Parsing {file}"); let mut prog = mclangc::parser::parse_program(tokens, &cli)?; - // dbg!(&prog.ast); info!("Validating {file}"); mclangc::validator::validate_code(&mut prog)?; + dbg!(&prog.functions.len()); + for f in &prog.functions { + error!("owo {}", f.1.inner()); + } // dbg!(&prog.literals); progs.push((fp, prog)); } diff --git a/src/parser/ast/expr.rs b/src/parser/ast/expr.rs index 4b5b4c9..b963e82 100644 --- a/src/parser/ast/expr.rs +++ b/src/parser/ast/expr.rs @@ -30,6 +30,7 @@ pub enum Expr { }, MethodCall { left: Box>, + strct: Option, params: CallParams, }, @@ -37,12 +38,16 @@ pub enum Expr { FieldAccess { left: Box>>, right: Box>, - offset: usize + offset: usize, + l_typ: Option>, + r_typ: Option>, }, PtrFieldAccess { left: Box>>, right: Box>, - offset: usize + offset: usize, + l_typ: Option>, + r_typ: Option> }, ForLoop { init: Box, @@ -66,6 +71,9 @@ pub enum Expr { left: Box>, right: Box> }, + Self_ { + strct: Option + }, } #[derive(Debug, Clone, Hash, PartialEq, PartialOrd)] @@ -102,6 +110,12 @@ pub struct CallParams(pub Vec>); #[derive(Debug, Clone, PartialEq, PartialOrd, Hash)] pub struct Block(pub Vec); +impl Default for Block { + fn default() -> Self { + Self(vec![]) + } +} + #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Hash)] pub struct Path(pub Vec); diff --git a/src/parser/ast/literal.rs b/src/parser/ast/literal.rs index 7725c68..4daaf1d 100644 --- a/src/parser/ast/literal.rs +++ b/src/parser/ast/literal.rs @@ -9,10 +9,14 @@ pub enum Literal { Ident(Ident), String(TString), Char(Char), - Array(Vec>), + Array{ + items: Vec>, + item_size: Option, + }, Bool(bool), ArrayRepeat { val: Box>, + item_size: Option, count: usize, }, } @@ -22,28 +26,29 @@ impl Literal { let t = match self { Self::Number(_) => Type::Builtin { name: String::from("usize"), size: SIZE as u8, signed: false }, Self::Ident(ident) => Type::Owned(ident.clone()), - Self::String(_) => Type::Ref { inner: Box::new(Type::Owned(Ident(String::from("str")))), mutable: false}, + Self::String(str) if str.cstr => Type::Ref { inner: Box::new(Type::Owned(Ident(String::from("cstr")))), mutable: false}, + Self::String(str) if !str.cstr => Type::Ref { inner: Box::new(Type::Owned(Ident(String::from("str")))), mutable: false}, + Self::String(_) => unreachable!("stupid rust"), Self::Char(_) => Type::Owned(Ident(String::from("char"))), Self::Bool(_) => Type::Owned(Ident(String::from("bool"))), - Self::Array(arr) => { + Self::Array { items: 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(String::new(), Literal::Number(Number { val: 0, base: 10, signed: false }))) } } else { - let item = arr.first().unwrap(); + let mut item = arr.first().unwrap().clone(); let loc = item.loc().clone(); - let mut item = item.inner().clone(); Type::SizedArray { 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 } => { + Self::ArrayRepeat { val, count, ..} => { let loc = val.loc().clone(); - let mut val = val.inner().clone(); + let mut val = val.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 })))} } diff --git a/src/parser/ast/mod.rs b/src/parser/ast/mod.rs index 2fb5ca9..425dfc5 100644 --- a/src/parser/ast/mod.rs +++ b/src/parser/ast/mod.rs @@ -19,7 +19,7 @@ pub struct Scope { pub inner_scope: Option> } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct Program { pub ast: expr::Block, pub structs: HashMap>, @@ -32,7 +32,9 @@ pub struct Program { pub literals: HashMap, // string is id of literal pub struct_literals: HashMap, // string is id of literal pub scope: Option, - pub curr_fn_args: HashMap> + pub curr_fn_args: HashMap>, + pub curr_struct: Option, + pub included_files: Vec, } diff --git a/src/parser/ast/statement.rs b/src/parser/ast/statement.rs index 2cc4b40..c2ee1fa 100644 --- a/src/parser/ast/statement.rs +++ b/src/parser/ast/statement.rs @@ -1,8 +1,9 @@ -use std::collections::HashMap; +use std::{collections::HashMap, fmt::{Display, write}, sync::Mutex}; use anyhow::bail; +use lazy_static::lazy_static; use crate::{common::loc::LocBox, lerror}; @@ -70,6 +71,32 @@ pub struct Function { pub body: Option, // If None then its a type declaration } +impl Display for Function { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut extrn = String::new(); + let mut args = Vec::new(); + let mut ret_t = String::new(); + + if let Some(ex) = &self.qual_extern { + if ex.val.is_empty() { + extrn = format!("extern "); + } else { + extrn = format!("extern \"{}\"", ex.val); + } + } + + for arg in &self.params { + args.push(format!("{}: {}", arg.0, arg.1.inner())); + } + if let Some(ret) = &self.ret_type { + ret_t = format!(" -> {}", ret.inner()); + } + + + write!(f, "{extrn}fn {}({}){ret_t}", self.get_full_name_pretty(), args.join(", ")) + } +} + impl Function { pub fn get_full_name(&self) -> String { if let Some(sn) = &self.struct_name { @@ -138,7 +165,19 @@ pub enum ConstDataTyp { Array(Vec) } -pub fn get_constant_data_as_bytes(program: &Program, struct_items: &HashMap, value: LocBox, is_big_endian: bool, must_be_number: bool) -> anyhow::Result { +lazy_static!( + static ref CTX: Mutex = Mutex::new(ConstantCalcCtx::default()); +); + +#[derive(Debug, Default, Clone)] +struct ConstantCalcCtx { + current_array_item_size: Option, + current_struct_items: Option>, + current_struct_item_name: Option +} + + +pub fn get_constant_data_as_bytes(program: &Program, value: LocBox, is_big_endian: bool, must_be_number: bool) -> anyhow::Result { match value.inner() { Expr::Literal(_, lit) => { match lit { @@ -154,11 +193,28 @@ pub fn get_constant_data_as_bytes(program: &Program, struct_items: &HashMap>(); + if *cstr { + let mut val = val.chars().into_iter().map(|v| v as u8).collect::>(); val.push(0); + Ok(ConstDataTyp::Bytes(val)) + } else { + let mut buf = Vec::new(); + let mut inc = 0; + while inc < 8 { + buf.push(((val.len() << 8*inc) & 0xff) as u8); + inc += 1; + } + + if is_big_endian { + buf.reverse(); + } + let val = val.chars().into_iter().map(|v| v as u8).collect::>(); + Ok(ConstDataTyp::Array(vec![ + ConstDataTyp::Bytes(buf), + ConstDataTyp::Bytes(val) + ])) } - Ok(ConstDataTyp::Bytes(val)) } Literal::Number(Number { val, base: _, signed: _ }) => { let mut buf = Vec::new(); @@ -174,7 +230,7 @@ pub fn get_constant_data_as_bytes(program: &Program, struct_items: &HashMap { + Literal::Array { items: arr, item_size } => { if must_be_number { lerror!(value.loc(), "Expected number got array"); bail!("") @@ -183,20 +239,24 @@ pub fn get_constant_data_as_bytes(program: &Program, struct_items: &HashMap { + Literal::ArrayRepeat { val, count, item_size} => { if must_be_number { lerror!(value.loc(), "Expected number got repeating array"); bail!("") } - let val = get_constant_data_as_bytes(program, struct_items, (**val).clone(), is_big_endian, must_be_number)?; + CTX.lock().unwrap().current_array_item_size = *item_size; + let val = get_constant_data_as_bytes(program, (**val).clone(), is_big_endian, must_be_number)?; + CTX.lock().unwrap().current_array_item_size = None; let mut num = Vec::new(); let mut inc = 0; @@ -241,23 +301,31 @@ pub fn get_constant_data_as_bytes(program: &Program, struct_items: &HashMap { + let ctx = {CTX.lock().unwrap().clone()}; 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)?) + Ok(get_constant_data_as_bytes(program, 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 if let Some(struct_items) = ctx.current_struct_items && + let Some(typ) = struct_items.get(&ctx.current_struct_item_name.unwrap()) { + Ok(ConstDataTyp::Variable(name.clone(), *typ)) + } else if let Some(array_item_size) = {CTX.lock().unwrap().clone()}.current_array_item_size { + Ok(ConstDataTyp::Variable(name.clone(), array_item_size)) } else { lerror!(value.loc(), "Unable to find ident '{name}'"); bail!("") diff --git a/src/parser/ast/typ.rs b/src/parser/ast/typ.rs index da1fb02..d95012d 100644 --- a/src/parser/ast/typ.rs +++ b/src/parser/ast/typ.rs @@ -2,7 +2,7 @@ use std::fmt::Display; use anyhow::bail; -use crate::{common::loc::LocBox, validator::predefined::get_builtin_from_name}; +use crate::{common::loc::LocBox, info, validator::predefined::{BuiltinType, get_builtin_from_name}}; use super::{expr::Expr, literal::Literal, Ident, Program}; @@ -28,6 +28,53 @@ pub enum Type { } impl Type { + pub fn is_void(&self) -> bool { + *self == BuiltinType::void() + } + pub fn as_ref(self) -> Self { + Self::Ref { + inner: Box::new(self), + mutable: false + } + } + pub fn as_ref_mut(self) -> Self { + Self::Ref { + inner: Box::new(self), + mutable: true + } + } + pub fn new_builtin(name: &str, size: u8, signed: bool) -> Self { + Self::Builtin { name: name.to_string(), size, signed } + } + pub fn should_deref_pointer(&self, program: &Program) -> bool { + dbg!(&self); + let mut slf = self.clone(); + match &mut slf { + Self::Ref { inner, .. } => { + match inner.as_mut() { + Self::Ref { .. } => true, + Self::Owned(ident) => { + if program.structs.get(ident).is_some() { + false + } else + if let Some(typ) = program.types.get(ident) { + **inner = typ.inner().clone(); + slf.should_deref_pointer(program) + } else { + false + } + } + _ => true, + } + }, + Self::Owned(_) | + Self::SizedArray { .. } | + Self::Builtin { .. } | + Self::UnsizedArray { .. } => false, + + + } + } pub fn get_absolute_value(&self, program: &Program) -> anyhow::Result { match self { Self::Ref { inner, .. } => inner.get_absolute_value(program), @@ -57,12 +104,42 @@ impl Type { } } + pub fn convert_owned_to_real_type(&mut self, program: &Program) { + match self { + Self::Owned(ident) => { + if let Some(t) = crate::validator::predefined::get_builtin_from_name(&ident.0) { + *self = t; + } else + if let Some(t) = program.types.get(ident) { + *self = t.inner().clone(); + } else + if let Some(t) = program.curr_fn_args.get(ident) { + *self = t.inner().clone(); + } else + if let Some(var) = program.get_var(ident) { + *self = var.1.inner().typ.clone().expect("type should be computed if were already using it").inner().clone(); + } + } + Self::Ref { inner, .. } | + Self::SizedArray { inner, .. } | + Self::UnsizedArray { inner, .. } => inner.convert_owned_to_real_type(program), + Self::Builtin { .. } => (), + } + } pub fn get_variable_type(&self, program: &Program) -> anyhow::Result { match self { Self::Owned(ident) => { - if let Some(t) = program.types.get(ident) { + dbg!(&ident); + dbg!(&crate::validator::predefined::get_builtin_from_name(&ident.0)); + if let Some(t) = crate::validator::predefined::get_builtin_from_name(&ident.0) { + Ok(t) + } else + if let Some(t) = program.types.get(ident) { Ok(t.inner().clone()) } else + if let Some(t) = program.curr_fn_args.get(ident) { + return 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 { diff --git a/src/parser/expr.rs b/src/parser/expr.rs index 2135dc3..360e75f 100644 --- a/src/parser/expr.rs +++ b/src/parser/expr.rs @@ -2,7 +2,7 @@ use std::collections::{BTreeMap, HashMap}; use anyhow::{bail, Result}; -use crate::{cli::CliArgs, common::loc::LocBox, debug, lerror, parser::{Punctuation, ast::expr::StructLit, typ::parse_type}, tokeniser::Token}; +use crate::{cli::CliArgs, common::loc::LocBox, debug, lerror, parser::{Punctuation, ast::{Program, 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}; @@ -37,14 +37,17 @@ const BINOP_LIST: &[TokenType] = &[ TokenType::Punct(Punctuation::Ge), ]; -pub fn parse_expr(tokens: &mut Vec, precedence: usize, consume_semi: bool, cli: &CliArgs) -> Result>> { +pub fn parse_expr(tokens: &mut Vec, precedence: usize, consume_semi: bool, cli: &CliArgs, prog: &mut Program) -> Result>> { let res = if let Some(_) = utils::check(tokens, TokenType::Delim(Delimiter::ParenL)) { - Some(parse_group(tokens, cli)?) + Some(parse_group(tokens, cli, prog)?) + } else + if let Some(kw) = utils::check_consume(tokens, TokenType::Keyword(Keyword::Self_)) { + Some(LocBox::new(kw.loc(), Expr::Self_ { strct: None })) } else if let Some(_) = utils::check(tokens, TokenType::ident("")) { let p = parse_path(tokens)?; - if let Some(t) = utils::check(tokens, TokenType::Delim(Delimiter::CurlyL)) { - Some(parse_struct_literal(tokens, p.inner().unwrap_path(), cli)?) + if let Some(_) = utils::check(tokens, TokenType::Delim(Delimiter::CurlyL)) { + Some(parse_struct_literal(tokens, p.inner().unwrap_path(), cli, prog)?) } else { Some(p) } @@ -56,7 +59,7 @@ pub fn parse_expr(tokens: &mut Vec, precedence: usize, consume_semi: bool TokenType::Punct(Punctuation::Ampersand), TokenType::Punct(Punctuation::Star), ]) { - Some(parse_unop(tokens, cli)?) + Some(parse_unop(tokens, cli, prog)?) } else if let Some(_) = utils::check_from_many(tokens, &[ TokenType::string("", false), @@ -66,15 +69,15 @@ pub fn parse_expr(tokens: &mut Vec, precedence: usize, consume_semi: bool TokenType::Keyword(Keyword::True), TokenType::Keyword(Keyword::False) ]) { - Some(parse_literal(tokens, cli)?) + Some(parse_literal(tokens, cli, prog)?) } else if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::While)) { - return Ok(Some(parse_while_loop(tokens, cli)?)); + return Ok(Some(parse_while_loop(tokens, cli, prog)?)); } else if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::For)) { - return Ok(Some(parse_for_loop(tokens, cli)?)); + return Ok(Some(parse_for_loop(tokens, cli, prog)?)); } else if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::Loop)) { - return Ok(Some(parse_inf_loop(tokens, cli)?)); + return Ok(Some(parse_inf_loop(tokens, cli, prog)?)); } else if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::Return)) { - return Ok(Some(parse_return(tokens, cli)?)); + return Ok(Some(parse_return(tokens, cli, prog)?)); } 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))); @@ -82,7 +85,7 @@ pub fn parse_expr(tokens: &mut Vec, precedence: usize, consume_semi: bool 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, cli)?)))); + return Ok(Some(LocBox::new(&kw.loc().clone(), Expr::If(parse_if(tokens, cli, prog)?)))); } else { None }; @@ -96,17 +99,17 @@ pub fn parse_expr(tokens: &mut Vec, precedence: usize, consume_semi: bool res = parse_ptr_field_access(tokens, res)?; } if utils::check(tokens, TokenType::Delim(Delimiter::ParenL)).is_some() { - res = parse_fn_call(tokens, res, cli)?; + res = parse_fn_call(tokens, res, cli, prog)?; } if utils::check(tokens, TokenType::Keyword(Keyword::As)).is_some() { res = parse_cast(tokens, res)?; } if utils::check(tokens, TokenType::Delim(Delimiter::SquareL)).is_some() { - res = parse_array_index(tokens, res, cli)?; + res = parse_array_index(tokens, res, cli, prog)?; } if let Some(_) = utils::check_from_many(tokens, BINOP_LIST) { - let v = parse_binop(tokens, res, precedence, cli)?; + let v = parse_binop(tokens, res, precedence, cli, prog)?; if consume_semi { _ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), "Expected ; at the end of the expression")?; } @@ -124,9 +127,9 @@ pub fn parse_expr(tokens: &mut Vec, precedence: usize, consume_semi: bool Ok(res) } -fn parse_return(tokens: &mut Vec, cli: &CliArgs) -> Result> { +fn parse_return(tokens: &mut Vec, cli: &CliArgs, prog: &mut Program) -> Result> { let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Return), "")?; - let item = parse_expr(tokens, 0, true, cli)?; + let item = parse_expr(tokens, 0, true, cli, prog)?; Ok(LocBox::new(kw.loc(), Expr::Return(Box::new(item)))) } @@ -138,10 +141,10 @@ fn parse_cast(tokens: &mut Vec, left: LocBox) -> Result, cli: &CliArgs) -> Result { +fn parse_if(tokens: &mut Vec, cli: &CliArgs, prog: &mut Program) -> Result { 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, cli)? else { + let Some(test) = parse_expr(tokens, 0, false, cli, prog)? else { lerror!(loc.loc(), "Expected test for if statement, got nothing"); bail!("") }; @@ -151,7 +154,7 @@ fn parse_if(tokens: &mut Vec, cli: &CliArgs) -> Result { _ = utils::check_consume(tokens, TokenType::Delim(Delimiter::CurlyR)); Block(Vec::new()) } else { - parse_block(tokens, cli)? + parse_block(tokens, cli, prog)? } } else { lerror!(loc.loc(), "Expected '{{'"); @@ -159,14 +162,14 @@ fn parse_if(tokens: &mut Vec, cli: &CliArgs) -> Result { }; if let Some(_) = utils::check_consume(tokens, TokenType::Keyword(Keyword::Else)) { if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::If)) { - let branch = IfBranchExpr::ElseIf(Box::new(parse_if(tokens, cli)?)); + let branch = IfBranchExpr::ElseIf(Box::new(parse_if(tokens, cli, prog)?)); Ok(IfExpr { test: Box::new(test), body: block, else_if: Some(branch) }) } else { - let branch = IfBranchExpr::Else(parse_block(tokens, cli)?); + let branch = IfBranchExpr::Else(parse_block(tokens, cli, prog)?); Ok(IfExpr { test: Box::new(test), body: block, @@ -181,39 +184,39 @@ fn parse_if(tokens: &mut Vec, cli: &CliArgs) -> Result { }) } } -fn parse_while_loop(tokens: &mut Vec, cli: &CliArgs) -> Result> { +fn parse_while_loop(tokens: &mut Vec, cli: &CliArgs, prog: &mut Program) -> Result> { 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, cli)? else { + let Some(test) = parse_expr(tokens, 0, false, cli, prog)? 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, cli)?; + let block = parse_block(tokens, cli, prog)?; Ok(LocBox::new(kw.loc(), Expr::WhileLoop { test: Box::new(test), body: block })) } -fn parse_for_loop(tokens: &mut Vec, cli: &CliArgs) -> Result> { +fn parse_for_loop(tokens: &mut Vec, cli: &CliArgs, prog: &mut Program) -> Result> { 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, cli)? else { + let Some(pre) = parse_item(tokens, cli, prog)? else { lerror!(kw.loc(), "Expected init stat for a for loop, got nothing"); bail!("") }; // Semicolon parsed out by parse_item above - let Some(test) = parse_expr(tokens, 0, false, cli)? else { + let Some(test) = parse_expr(tokens, 0, false, cli, prog)? else { lerror!(kw.loc(), "Expected test comparrison for a for loop, got nothing"); bail!("") }; _ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), ""); - let Some(post) = parse_expr(tokens, 0, false, cli)? else { + let Some(post) = parse_expr(tokens, 0, false, cli, prog)? else { 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, cli)?; + let block = parse_block(tokens, cli, prog)?; Ok(LocBox::new(kw.loc(), Expr::ForLoop { init: Box::new(pre), @@ -222,16 +225,16 @@ fn parse_for_loop(tokens: &mut Vec, cli: &CliArgs) -> Result body: block })) } -fn parse_inf_loop(tokens: &mut Vec, cli: &CliArgs) -> Result> { +fn parse_inf_loop(tokens: &mut Vec, cli: &CliArgs, prog: &mut Program) -> Result> { let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Loop), "")?; - let block = parse_block(tokens, cli)?; + let block = parse_block(tokens, cli, prog)?; Ok(LocBox::new(kw.loc(), Expr::InfLoop { body: block })) } -fn parse_fn_call(tokens: &mut Vec, left: LocBox, cli: &CliArgs) -> Result> { +fn parse_fn_call(tokens: &mut Vec, left: LocBox, cli: &CliArgs, prog: &mut Program) -> Result> { match left.inner() { Expr::FieldAccess { .. } | Expr::PtrFieldAccess { .. } => { - return parse_member_function_call(tokens, left, cli); + return parse_member_function_call(tokens, left, cli, prog); } _ => () } @@ -244,7 +247,7 @@ fn parse_fn_call(tokens: &mut Vec, left: LocBox, cli: &CliArgs) -> if let Some(_) = utils::check(tokens, TokenType::Delim(Delimiter::ParenR)) { break; } - let Some(param) = parse_expr(tokens, 0, false, cli)? else {break}; + let Some(param) = parse_expr(tokens, 0, false, cli, prog)? 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)) { @@ -256,9 +259,9 @@ fn parse_fn_call(tokens: &mut Vec, left: LocBox, cli: &CliArgs) -> _ = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenR), ""); Ok(LocBox::new(start.loc(), Expr::Call { path: Box::new(left), params: CallParams(params) })) } -fn parse_array_index(tokens: &mut Vec, left: LocBox, cli: &CliArgs) -> Result> { +fn parse_array_index(tokens: &mut Vec, left: LocBox, cli: &CliArgs, prog: &mut Program) -> Result> { let start = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::SquareL), "")?; - let Some(idx) = parse_expr(tokens, 0, false, cli)? else { + let Some(idx) = parse_expr(tokens, 0, false, cli, prog)? else { lerror!(start.loc(), "Expected index for in array index but found nothing."); bail!("") }; @@ -284,11 +287,13 @@ fn parse_field_access(tokens: &mut Vec, left: LocBox) -> Result, left: LocBox, cli: &CliArgs) -> Result> { +fn parse_member_function_call(tokens: &mut Vec, left: LocBox, cli: &CliArgs, prog: &mut Program) -> Result> { let start = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenL), "unreachable")?; let mut params = Vec::new(); @@ -296,7 +301,7 @@ fn parse_member_function_call(tokens: &mut Vec, left: LocBox, cli: if let Some(_) = utils::check(tokens, TokenType::Delim(Delimiter::ParenR)) { break; } - let Some(param) = parse_expr(tokens, 0, false, cli)? else {break}; + let Some(param) = parse_expr(tokens, 0, false, cli, prog)? 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)) { @@ -308,7 +313,8 @@ fn parse_member_function_call(tokens: &mut Vec, left: LocBox, cli: _ = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenR), ""); Ok(LocBox::new(start.loc(), Expr::MethodCall { - left: Box::new(left), + left: Box::new(left), + strct: None, params: CallParams(params) })) } @@ -327,11 +333,13 @@ fn parse_ptr_field_access(tokens: &mut Vec, left: LocBox) -> Result Ok(LocBox::new(start.loc(), Expr::PtrFieldAccess { left: Box::new(Some(left)), right: Box::new(right), - offset: 0 + offset: 0, + l_typ: None, + r_typ: None })) } -fn parse_literal(tokens: &mut Vec, cli: &CliArgs) -> Result> { +fn parse_literal(tokens: &mut Vec, cli: &CliArgs, prog: &mut Program) -> Result> { 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 @@ -352,17 +360,17 @@ fn parse_literal(tokens: &mut Vec, cli: &CliArgs) -> Result> } 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(String::new(), Literal::Array(Vec::new())))); + return Ok(LocBox::new(start.loc(), Expr::Literal(String::new(), Literal::Array { items: Vec::new(), item_size: None }))); } /*if *tokens[tokens.len()-2].tt() == TokenType::Punct(Punctuation::Comma) { } else */ if *tokens[tokens.len()-2].tt() == TokenType::Punct(Punctuation::Semi) { - let Some(typ) = parse_expr(tokens, 0, true, cli)? else { + let Some(typ) = parse_expr(tokens, 0, true, cli, prog)? else { lerror!(start.loc(), "Expected value, found nothing"); bail!("") }; - let count = parse_expr(tokens, 0, false, cli)?.unwrap(); + let count = parse_expr(tokens, 0, false, cli, prog)?.unwrap(); let Expr::Literal(_, Literal::Number(count)) = count.inner() else { lerror!(count.loc(), "a repeating array accepts only literal numbers for count argument"); @@ -371,16 +379,14 @@ fn parse_literal(tokens: &mut Vec, cli: &CliArgs) -> Result> utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::SquareR), "")?; return Ok(LocBox::new(start.loc(), Expr::Literal(String::new(), Literal::ArrayRepeat { val: Box::new(typ), - count: count.val + count: count.val, + item_size: None, }))); } else { - let first = parse_expr(tokens, 0, false, cli)?; - let Some(first) = first else { unreachable!() }; let mut values = Vec::new(); - values.push(first); while !tokens.is_empty() { - let Some(val) = parse_expr(tokens, 0, false, cli)? else{break}; + let Some(val) = parse_expr(tokens, 0, false, cli, prog)? else{break}; values.push(val); if let None = utils::check_consume(tokens, TokenType::Punct(Punctuation::Comma)) { @@ -388,7 +394,7 @@ fn parse_literal(tokens: &mut Vec, cli: &CliArgs) -> Result> } } utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::SquareR), "")?; - return Ok(LocBox::new(start.loc(), Expr::Literal(String::new(), Literal::Array(values)))); + return Ok(LocBox::new(start.loc(), Expr::Literal(String::new(), Literal::Array { items: values, item_size: None }))); /* if let Some(curr) = tokens.last() { lerror!(start.loc(), "Expected a , or ; as a separator in a literal array (normal, or repeating, respectively), but found {}", curr.tt()); @@ -402,7 +408,7 @@ fn parse_literal(tokens: &mut Vec, cli: &CliArgs) -> Result> unreachable!() } -fn parse_struct_literal(tokens: &mut Vec, name: Path, cli: &CliArgs) -> Result> { +fn parse_struct_literal(tokens: &mut Vec, name: Path, cli: &CliArgs, prog: &mut Program) -> Result> { let start = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::CurlyL), "")?; let mut fields = BTreeMap::new(); while !tokens.is_empty() { @@ -412,7 +418,7 @@ fn parse_struct_literal(tokens: &mut Vec, name: Path, cli: &CliArgs) -> R let name = utils::check_consume_or_err(tokens, TokenType::ident(""), "")?; _ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Colon), "wtf?")?; - let typ = parse_expr(tokens, 0, false, cli)?.unwrap(); + let typ = parse_expr(tokens, 0, false, cli, prog)?.unwrap(); fields.insert(name.tt().unwrap_ident(), typ); if let None = utils::check_consume(tokens, TokenType::Punct(Punctuation::Comma)) { utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::CurlyR), "")?; @@ -422,9 +428,9 @@ fn parse_struct_literal(tokens: &mut Vec, name: Path, cli: &CliArgs) -> R Ok(LocBox::new(start.loc(), Expr::Struct(String::new(), StructLit { path: name, fields }))) } -fn parse_group(tokens: &mut Vec, cli: &CliArgs) -> Result> { +fn parse_group(tokens: &mut Vec, cli: &CliArgs, prog: &mut Program) -> Result> { let start = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenL), "")?; - let Some(expr) = parse_expr(tokens, 0, false, cli)? else { + let Some(expr) = parse_expr(tokens, 0, false, cli, prog)? else { lerror!(start.loc(), "Expected expr found nothing"); bail!("") }; @@ -449,7 +455,7 @@ fn parse_path(tokens: &mut Vec) -> Result> { Ok(LocBox::new(part.loc(), Expr::Path(Path(buf)))) } -fn parse_unop(tokens: &mut Vec, cli: &CliArgs) -> Result> { +fn parse_unop(tokens: &mut Vec, cli: &CliArgs, prog: &mut Program) -> Result> { let typ = utils::check_consume_or_err_from_many(tokens, &[ TokenType::Punct(Punctuation::Not), TokenType::Punct(Punctuation::Plus), // Make number positive @@ -460,7 +466,7 @@ fn parse_unop(tokens: &mut Vec, cli: &CliArgs) -> Result> { let loc = typ.loc().clone(); let TokenType::Punct(typ) = typ.tt().clone() else {unreachable!()}; - let Some(right) = parse_expr(tokens, 5, false, cli)? else { + let Some(right) = parse_expr(tokens, 5, false, cli, prog)? else { lerror!(&loc, "Expected expression after unary token, found nothing"); bail!("") }; @@ -470,7 +476,7 @@ fn parse_unop(tokens: &mut Vec, cli: &CliArgs) -> Result> { })) } -fn parse_binop(tokens: &mut Vec, mut lhs: LocBox, precedence: usize, cli: &CliArgs) -> Result> { +fn parse_binop(tokens: &mut Vec, mut lhs: LocBox, precedence: usize, cli: &CliArgs, prog: &mut Program) -> Result> { // TODO: https://en.wikipedia.org/wiki/Operator-precedence_parser#Pseudocode loop { @@ -501,7 +507,7 @@ fn parse_binop(tokens: &mut Vec, mut lhs: LocBox, precedence: usize } _ = tokens.pop(); - let Some(rhs) = parse_expr(tokens, rp, false, cli)? else {break;}; + let Some(rhs) = parse_expr(tokens, rp, false, cli, prog)? else {break;}; lhs = LocBox::new(&op_loc, Expr::BinOp { typ: op, left: Box::new(lhs), @@ -515,14 +521,14 @@ fn parse_binop(tokens: &mut Vec, mut lhs: LocBox, precedence: usize } -pub fn parse_block(tokens: &mut Vec, cli: &CliArgs) -> Result { +pub fn parse_block(tokens: &mut Vec, cli: &CliArgs, prog: &mut Program) -> Result { utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::CurlyL), "")?; let mut items = Vec::new(); while !tokens.is_empty() { if let Some(_) = utils::check(tokens, TokenType::Delim(Delimiter::CurlyR)) { break; } - if let Some(item) = parse_item(tokens, cli)? { + if let Some(item) = parse_item(tokens, cli, prog)? { items.push(item); } else { break; diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 92073d1..f3c4ddc 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -14,18 +14,8 @@ type Result = anyhow::Result; pub fn parse_program(mut tokens: Vec, cli: &CliArgs) -> Result { let mut prog_body = Vec::new(); - - while !tokens.is_empty() { - if let Some(item) = parse_item(&mut tokens, cli)? { - prog_body.push(item); - } else { - break - } - } - - - Ok(Program { - ast: Block(prog_body), + let mut prog = Program { + ast: Block(prog_body.clone()), enums: HashMap::new(), functions: HashMap::new(), member_functions: HashMap::new(), @@ -36,15 +26,27 @@ pub fn parse_program(mut tokens: Vec, cli: &CliArgs) -> Result { literals: HashMap::new(), struct_literals: HashMap::new(), scope: None, - curr_fn_args: HashMap::new() - }) + curr_fn_args: HashMap::new(), + curr_struct: None, + included_files: Vec::new() + }; + while !tokens.is_empty() { + if let Some(item) = parse_item(&mut tokens, cli, &mut prog)? { + prog_body.push(item); + } else { + break + } + } + + prog.ast = Block(prog_body); + Ok(prog) } -fn parse_item(tokens: &mut Vec, cli: &CliArgs) -> Result> { - if let Some(stat) = stat::parse_statement(tokens, cli)? { +fn parse_item(tokens: &mut Vec, cli: &CliArgs, prog: &mut Program) -> Result> { + if let Some(stat) = stat::parse_statement(tokens, cli, prog)? { return Ok(Some(Ast::Statement(stat))); } - if let Some(expr) = expr::parse_expr(tokens, 0, true, cli)? { + if let Some(expr) = expr::parse_expr(tokens, 0, true, cli, prog)? { return Ok(Some(Ast::Expr(expr))); } Ok(None) diff --git a/src/parser/stat.rs b/src/parser/stat.rs index aa81f48..cce96c0 100644 --- a/src/parser/stat.rs +++ b/src/parser/stat.rs @@ -1,9 +1,11 @@ +use std::str; + use anyhow::bail; use crate::cli::CliArgs; use crate::common::loc::LocBox; -use crate::{cli, lerror}; -use crate::parser::ast::{TString, TokenType}; +use crate::{cli, error, lerror}; +use crate::parser::ast::{Program, TString, TokenType}; use crate::parser::ast::statement::Let; use crate::parser::expr::parse_expr; use crate::parser::{Delimiter, Ident, Keyword, Punctuation}; @@ -16,18 +18,18 @@ use super::ast::statement::{ConstVar, Enum, Function, Statement, StaticVar, Stru type Result = anyhow::Result; -pub fn parse_statement(tokens: &mut Vec, cli: &CliArgs) -> Result>> { +pub fn parse_statement(tokens: &mut Vec, cli: &CliArgs, prog: &mut Program) -> Result>> { if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::Fn)) { - Ok(Some(parse_fn(tokens, cli)?)) + Ok(Some(parse_fn(tokens, cli, prog)?)) } else if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::Type)) { Ok(Some(parse_type_alias(tokens)?)) } else if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::Const)) { - Ok(Some(parse_constant(tokens, cli)?)) + Ok(Some(parse_constant(tokens, cli, prog)?)) } else if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::Static)) { - Ok(Some(parse_static(tokens, cli)?)) + Ok(Some(parse_static(tokens, cli, prog)?)) } else if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::Struct)) { Ok(Some(parse_struct(tokens)?)) @@ -36,17 +38,17 @@ pub fn parse_statement(tokens: &mut Vec, cli: &CliArgs) -> Result, cli: &CliArgs) -> Result> { +fn parse_include(tokens: &mut Vec, cli: &CliArgs, prog: &mut Program) -> Result> { let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Include), "")?; let TokenType::String(include_path) = utils::check_consume_or_err(tokens, TokenType::String(TString::default()), "")?.tt().clone() else {panic!()}; _ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), "")?; @@ -56,6 +58,13 @@ fn parse_include(tokens: &mut Vec, cli: &CliArgs) -> Result) -> Result> { Ok(LocBox::new(kw.loc(), Statement::Struct(Struct { name, fields }))) } -fn parse_static(tokens: &mut Vec, cli: &CliArgs) -> Result> { +fn parse_static(tokens: &mut Vec, cli: &CliArgs, prog: &mut Program) -> Result> { let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Static), "")?; let name = utils::check_consume_or_err(tokens, TokenType::ident(""), "")?.tt().unwrap_ident(); _ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Colon), "")?; let typ = parse_type(tokens)?; let eq = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Eq), "")?; - let Some(val) = parse_expr(tokens, 0, false, cli)? else { + let Some(val) = parse_expr(tokens, 0, false, cli, prog)? else { lerror!(eq.loc(), "Expected expression found nothing"); bail!("") }; @@ -137,7 +146,7 @@ fn parse_static(tokens: &mut Vec, cli: &CliArgs) -> Result, cli: &CliArgs) -> Result> { +fn parse_let(tokens: &mut Vec, cli: &CliArgs, prog: &mut Program) -> Result> { let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Let), "")?; let name = utils::check_consume_or_err(tokens, TokenType::ident(""), "")?.tt().unwrap_ident(); let mut typ = None; @@ -146,7 +155,7 @@ fn parse_let(tokens: &mut Vec, cli: &CliArgs) -> Result typ = Some(parse_type(tokens)?); } if let Some(eq) = utils::check_consume(tokens, TokenType::Punct(Punctuation::Eq)) { - let Some(_val) = parse_expr(tokens, 0, false, cli)? else { + let Some(_val) = parse_expr(tokens, 0, false, cli, prog)? else { lerror!(eq.loc(), "Expected expression found nothing"); bail!("") }; @@ -155,7 +164,7 @@ fn parse_let(tokens: &mut Vec, cli: &CliArgs) -> Result _ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), "")?; Ok(LocBox::new(kw.loc(), Statement::Let(Let{ name, typ, val }))) } -fn parse_constant(tokens: &mut Vec, cli: &CliArgs) -> Result> { +fn parse_constant(tokens: &mut Vec, cli: &CliArgs, prog: &mut Program) -> Result> { let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Const), "")?; if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::Fn)) { @@ -165,7 +174,7 @@ fn parse_constant(tokens: &mut Vec, cli: &CliArgs) -> Result) -> Result> { Ok(LocBox::new(kw.loc(), Statement::TypeAlias(TypeAlias { name, typ }))) } -fn parse_fn(tokens: &mut Vec, cli: &CliArgs) -> Result> { +fn parse_fn(tokens: &mut Vec, cli: &CliArgs, prog: &mut Program) -> Result> { + error!("fnc"); // Just remove the kw since we checked it before let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Fn), "")?; - let mut struct_name = None; let mut name = utils::check_consume_or_err(tokens, TokenType::ident(""), "")?.tt().unwrap_ident(); // Check if this is a struct method @@ -194,7 +203,7 @@ fn parse_fn(tokens: &mut Vec, cli: &CliArgs) -> Result> struct_name = Some(name); name = utils::check_consume_or_err(tokens, TokenType::ident(""), "")?.tt().unwrap_ident(); } - let params = parse_fn_params(tokens)?; + let mut params_partial = parse_fn_params(tokens)?; // Check for return type cause it optional let mut ret_type = None; @@ -203,13 +212,22 @@ fn parse_fn(tokens: &mut Vec, cli: &CliArgs) -> Result> } let body; if let Some(_) = utils::check(tokens, TokenType::Delim(Delimiter::CurlyL)) { - body = Some(parse_block(tokens, cli)?); + body = Some(parse_block(tokens, cli, prog)?); } else { // Check if its just a declaration _ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), "")?; body = None; } - + let mut params = Vec::new(); + if let Some(name) = &struct_name { + match params_partial.0 { + 1 => params.push((Ident(String::from("self")), LocBox::new(kw.loc(), Type::Owned(name.clone()).as_ref()))), + 2 => params.push((Ident(String::from("self")), LocBox::new(kw.loc(), Type::Owned(name.clone()).as_ref_mut()))), + _ => () + } + } + + params.append(&mut params_partial.1); Ok(LocBox::new(kw.loc(), Statement::Fn(Function{ struct_name, name, @@ -222,10 +240,23 @@ fn parse_fn(tokens: &mut Vec, cli: &CliArgs) -> Result> } - -fn parse_fn_params(tokens: &mut Vec) -> Result)>> { +// usize is: 0 = no self, static; 1 = self, ref; 2 = self, mut ref +fn parse_fn_params(tokens: &mut Vec) -> Result<(usize, Vec<(Ident, LocBox)>)> { let mut args = Vec::new(); + utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenL), "")?; + + let mut dis = 0; + + if let Some(_) = utils::check_consume(tokens, TokenType::Punct(Punctuation::Ampersand)) { + if let Some(_) = utils::check_consume(tokens, TokenType::Keyword(Keyword::Mut)) { + _ = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Self_), "Expected 'this' keyword after &mut")?; + dis = 1 + } else { + _ = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Self_), "Expected 'this' keyword after &")?; + dis = 2 + } + } while !tokens.is_empty() { if let Some(_) = utils::check(tokens, TokenType::Delim(Delimiter::ParenR)) { break; @@ -242,7 +273,7 @@ fn parse_fn_params(tokens: &mut Vec) -> Result)> } utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenR), "")?; - Ok(args) + Ok((dis, args)) } diff --git a/src/parser/typ.rs b/src/parser/typ.rs index 7dcff38..5b7345a 100644 --- a/src/parser/typ.rs +++ b/src/parser/typ.rs @@ -1,6 +1,6 @@ use anyhow::{Result, bail}; -use crate::{cli::CliArgs, common::loc::LocBox, lerror, parser::{Delimiter, ast::{expr::Expr, literal::Literal}}, tokeniser::Token}; +use crate::{cli::CliArgs, common::loc::LocBox, lerror, parser::{Delimiter, ast::{Program, expr::Expr, literal::Literal}}, tokeniser::Token, validator::predefined::get_builtin_from_name}; use super::{ast::{typ::Type, TokenType}, expr::parse_expr, utils, Keyword, Punctuation}; @@ -25,7 +25,7 @@ pub fn parse_type(tokens: &mut Vec) -> Result> { } let itm_typ = parse_type(tokens)?; if let Some(_) = utils::check_consume(tokens, TokenType::Punct(Punctuation::Semi)) { - let count = parse_expr(tokens, 0, false, &CliArgs::default())?.unwrap(); + let count = parse_expr(tokens, 0, false, &CliArgs::default(), &mut Program::default())?.unwrap(); match count.inner() { Expr::Literal(_, Literal::Number(_)) | @@ -47,7 +47,11 @@ pub fn parse_type(tokens: &mut Vec) -> Result> { _ = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::SquareR), "")?; } else { let ident = utils::check_consume_or_err(tokens, TokenType::ident(""), "a")?; - typ = Type::Owned(ident.tt().unwrap_ident()); + if let Some(t) = get_builtin_from_name(&ident.tt().unwrap_ident().0) { + typ = t; + } else { + typ = Type::Owned(ident.tt().unwrap_ident()); + } if let None = loc { loc = Some(ident.loc().clone()); } diff --git a/src/targets/mod.rs b/src/targets/mod.rs index 2af9308..2de5425 100644 --- a/src/targets/mod.rs +++ b/src/targets/mod.rs @@ -56,7 +56,7 @@ pub fn compile(cli: &CliArgs, programs: Vec<(PathBuf, Program)>) -> anyhow::Resu objs.push(obj_p); } let out = Path::new(&cli.output); - target.link(objs, &out)?; + target.link(objs, &out, &cli.linker_args)?; Ok(()) } @@ -71,5 +71,5 @@ pub trait Target { } fn write_code(&mut self, program: &Program, f: &mut File) -> anyhow::Result<()>; fn compile(&mut self, from: &Path, to: &Path) -> anyhow::Result<()>; - fn link(&mut self, from: Vec, to: &Path) -> anyhow::Result<()>; + fn link(&mut self, from: Vec, to: &Path, extra_args: &Vec) -> anyhow::Result<()>; } diff --git a/src/targets/x86_64/asmgen/linux/mod.rs b/src/targets/x86_64/asmgen/linux/mod.rs index a8de32a..4c3a1d9 100644 --- a/src/targets/x86_64/asmgen/linux/mod.rs +++ b/src/targets/x86_64/asmgen/linux/mod.rs @@ -1,4 +1,4 @@ -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 crate::{common::{Loc, loc::LocBox}, parser::ast::{Ast, Ident, Program, Punctuation, expr::{Expr, IfBranchExpr, Path}, literal::Literal, statement::{ConstDataTyp, Function, Statement, get_constant_data_as_bytes}, typ::Type}, targets::Target}; use std::{collections::HashMap, fs::File, io::Write, process}; pub struct AsmGen; @@ -54,13 +54,16 @@ impl Target for AsmGen { cmd.output()?; Ok(()) } - fn link(&mut self, from: Vec, to: &std::path::Path) -> anyhow::Result<()> { + fn link(&mut self, from: Vec, to: &std::path::Path, extra_args: &Vec) -> anyhow::Result<()> { let mut cmd = std::process::Command::new("ld"); + cmd.args(extra_args); + 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()); } @@ -79,7 +82,6 @@ pub enum VarMapT { pub struct FunctionCtx { vars: HashMap, 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 @@ -93,7 +95,6 @@ impl FunctionCtx { Self { vars: Default::default(), stack_offset: 0, - used_registers: 0, loop_level: 0, if_level: 0, cmp_level: 0, @@ -171,6 +172,7 @@ impl AsmGen { } else { func.name.to_string() }; + info!("writing norm function: {name}"); writeln!(f, "{}: ; {} {}", name, loc, func.get_full_name_pretty())?; if body.0.is_empty() { writeln!(f, " ret")?; @@ -216,6 +218,7 @@ impl AsmGen { } } } else { + info!("writing function stub: {}", func.name); writeln!(f, " ret")?; } writeln!(f, "\n")?; @@ -245,21 +248,38 @@ impl AsmGen { } pub fn write_expr(&self, program: &Program, f: &mut impl Write, fc: &mut FunctionCtx, expr: &Expr) -> anyhow::Result<()> { match expr { - Expr::Cast { .. } => (), + Expr::Cast { left, .. } => self.write_expr(program, f, fc, left.inner())?, Expr::Literal(id, val) => { match val { + Literal::Array{ items, item_size } => { + dbg!(&val); + writeln!(f, " lea r10, [rel mcl_lit_{id}] ; arr")?; + for (i, item) in items.iter().enumerate() { + self.write_expr(program, f, fc, item.inner())?; + let offset = i * item_size.unwrap(); + writeln!(f, " mov [r10+{offset}], rax")?; + } + writeln!(f, " mov rax, r10")?; + } + Literal::ArrayRepeat { val, item_size, count} => { + writeln!(f, " lea r10, [rel mcl_lit_{id}] ; arr repeat")?; + for i in 0..*count { + self.write_expr(program, f, fc, val.inner())?; + let offset = i * item_size.unwrap(); + writeln!(f, " mov [r10+{offset}], rax")?; + } + writeln!(f, " mov rax, r10")?; + }, Literal::Ident(_) => unreachable!(), - Literal::Array(_) | - Literal::String(_) | - Literal::ArrayRepeat { .. } => { - writeln!(f, " lea rax, [rel mcl_lit_{id}]")?; + Literal::String(_) => { + writeln!(f, " lea rax, [rel mcl_lit_{id}] ; str")?; } Literal::Bool(v) => { writeln!(f, " mov rax, {} ; {}", *v as u8, v)?; } Literal::Number(_) | Literal::Char(_) => { - writeln!(f, " mov rax, [rel mcl_lit_{id}]")?; + writeln!(f, " mov rax, [rel mcl_lit_{id}] ; num/char")?; } } } @@ -271,15 +291,30 @@ impl AsmGen { let offset = strct_t.inner().get_offset_of(program, name)?; writeln!(f, " mov [r10+{offset}], rax")?; } + writeln!(f, " mov rax, r10")?; } - Expr::PtrFieldAccess { left, right, offset } => { + Expr::PtrFieldAccess { left, right, offset, l_typ, r_typ } => { self.write_expr(program, f, fc, left.clone().unwrap().inner())?; - writeln!(f, " add rax, {offset} ; ->{:?}", right.inner())?; + dbg!(&l_typ); + if l_typ.clone().unwrap().should_deref_pointer(program) { + writeln!(f, " mov rax, [rel rax] ; rqawr ->{:?}", right.inner())?; + } + if *offset > 0 { + writeln!(f, " add rax, {offset} ; ->{:?}", right.inner())?; + } + + if let Some(t) = r_typ && t.is_numeric(program) { + writeln!(f, " mov rax, [rax] ; ->{:?}", right.inner())?; + } }, - Expr::FieldAccess { left, right, offset } => { + Expr::FieldAccess { left, right, offset, l_typ: _, r_typ } => { 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())?; + if *offset > 0 { + writeln!(f, " add rax, {offset} ; .{:?}", right.inner())?; + } + if let Some(t) = r_typ && t.is_numeric(program) { + writeln!(f, " mov rax, [rax] ; .{:?}", right.inner())?; + } }, Expr::InfLoop { body } => { let sl = fc.inc_loop_level(); @@ -387,6 +422,35 @@ impl AsmGen { fc.is_last_item = false; } } + Expr::MethodCall { left, strct, params } => { + let method_name; + match left.inner() { + Expr::FieldAccess { left, right, .. } | + Expr::PtrFieldAccess { left, right, .. } => { + self.write_expr(program, f, fc, left.clone().unwrap().inner())?; + match right.inner() { + Expr::Path(path) => { + method_name = path.0.first().unwrap().clone(); + } + _ => unreachable!() + } + } + _ => unreachable!() + } + let reg = fc.register_id_to_str(0); + writeln!(f, " mov {reg}, rax")?; + 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+1); + writeln!(f, " mov {reg}, rax")?; + } else { + writeln!(f, " push rax")?; + } + } + + writeln!(f, " call {}", Path(vec![strct.clone().unwrap(), method_name]).display_asm_compat())?; + } Expr::Call { path, params } => { for (i, param) in params.0.iter().enumerate() { self.write_expr(program, f, fc, param.inner())?; @@ -550,16 +614,29 @@ impl AsmGen { match var { VarMapT::Stack(offset, typ) => { match typ { - Type::Builtin { .. } => writeln!(f, " lea rax, [rsp + {offset}]")?, - _ => writeln!(f, " mov rax, [rsp + {offset}]")?, + /*Type::Builtin { .. } => { + writeln!(f, " mov rax, [rsp+{offset}] ; var {ident}")?; + writeln!(f, " mov rax, [rax] ; var {ident}")?; + }*/ + _ => writeln!(f, " mov rax, [rsp+{offset}] ; var {ident}")?, } } } } else if let Some(_) = program.get_const_var(&ident) { - writeln!(f, " lea rax, [rel {ident}]")?; + writeln!(f, " lea rax, [rel {ident}] ; const {ident}")?; } else { panic!() } + + } + Expr::Self_ { strct: _ } => { + if let Some(var) = fc.get(&Ident::new("self")) { + match var { + VarMapT::Stack(offset, _) => { + writeln!(f, " mov rax, [rsp+{offset}] ; self")?; + } + } + } } v => unreachable!("{v:?}") } @@ -585,7 +662,7 @@ impl AsmGen { 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)?; + let bytes = get_constant_data_as_bytes(program, constant.val.clone(), false, false)?; fn x(bytes: &ConstDataTyp, f: &mut File) -> anyhow::Result<()> { match bytes { ConstDataTyp::Array(arr) => { @@ -622,7 +699,7 @@ impl AsmGen { 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)?; + let bytes = get_constant_data_as_bytes(program, statc.val.clone(), false, false)?; fn x(bytes: &ConstDataTyp, f: &mut File) -> anyhow::Result<()> { match bytes { ConstDataTyp::Array(arr) => { @@ -688,11 +765,11 @@ impl AsmGen { 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)?; + w(get_constant_data_as_bytes(program, 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)?; + w(get_constant_data_as_bytes(program, LocBox::new(&Loc::default(), Expr::Struct(lit.0.clone(), lit.1.clone())), false, false)?, f)?; } Ok(()) } diff --git a/src/targets/x86_64/asmgen/linux/runtime.s b/src/targets/x86_64/asmgen/linux/runtime.s index 976f9be..d5c42b1 100644 --- a/src/targets/x86_64/asmgen/linux/runtime.s +++ b/src/targets/x86_64/asmgen/linux/runtime.s @@ -1,36 +1,61 @@ -; 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" -__INTERNAL_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 + +__INTERNAL_syscall0: + mov rax, rdi + syscall + ret + +__INTERNAL_syscall1: + mov rax, rdi + mov rdi, rsi + syscall + ret + +__INTERNAL_syscall2: + mov rax, rdi + mov rdi, rsi + mov rsi, rdx + syscall + ret + +__INTERNAL_syscall3: + mov rax, rdi + mov rdi, rsi + mov rsi, rdx + mov rdx, rcx + syscall + ret + +__INTERNAL_syscall4: + mov rax, rdi + mov rdi, rsi + mov rsi, rdx + mov rdx, rcx + mov r10, r8 + syscall + ret + +__INTERNAL_syscall5: + mov rax, rdi + mov rdi, rsi + mov rsi, rdx + mov rdx, rcx + mov r10, r8 + mov r8, r9 + syscall + ret + +__INTERNAL_syscall6: + mov rax, rdi + mov rdi, rsi + mov rsi, rdx + mov rdx, rcx + mov r10, r8 + mov r8, r9 + mov r9, [rsp + 8] + syscall + ret + + global _start _start: xor rax, rax diff --git a/src/tokeniser/mod.rs b/src/tokeniser/mod.rs index 576da0f..5d799cd 100644 --- a/src/tokeniser/mod.rs +++ b/src/tokeniser/mod.rs @@ -30,6 +30,12 @@ impl Token { pub fn tt(&self) -> &TokenType { &self.tt } + pub fn new_test(tt: TokenType) -> Self { + Self { + loc: Loc::default(), + tt + } + } } @@ -81,6 +87,9 @@ pub fn tokenise(s: &str, file_p: &str) -> anyhow::Result> { buf.push(*c); last = *c; } + let buf = buf + .replace("\\n", "\n") + .replace("\\r", "\r"); tokens.push(Token::new(TokenType::string(&buf, false), &loc)); } '\'' => { @@ -251,6 +260,7 @@ lazy_static::lazy_static!( ("return", TokenType::Keyword(Keyword::Return)), ("loop", TokenType::Keyword(Keyword::Loop)), ("as", TokenType::Keyword(Keyword::As)), + ("self", TokenType::Keyword(Keyword::Self_)), ("{", TokenType::Delim(Delimiter::CurlyL)), ("}", TokenType::Delim(Delimiter::CurlyR)), ("[", TokenType::Delim(Delimiter::SquareL)), diff --git a/src/tokeniser/tokentype.rs b/src/tokeniser/tokentype.rs index 22e1fb3..a5a0910 100644 --- a/src/tokeniser/tokentype.rs +++ b/src/tokeniser/tokentype.rs @@ -16,6 +16,9 @@ impl Ident { pub fn as_path(self) -> Path { Path(vec![self]) } + pub fn new(s: impl ToString) -> Self { + Self(s.to_string()) + } } @@ -71,7 +74,7 @@ pub enum Keyword { Type, While, For, Break, Continue, Let, Const, Mut, Static, True, False, Include, Extern, Return, - As, Loop + As, Loop, Self_ } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/src/validator/mod.rs b/src/validator/mod.rs index d444af8..7796e2e 100644 --- a/src/validator/mod.rs +++ b/src/validator/mod.rs @@ -2,7 +2,7 @@ use std::{collections::HashMap, panic}; use anyhow::bail; -use crate::{common::{Loc, loc::LocBox}, parser::ast::{Ast, Program, Punctuation, Scope, TokenType, expr::*, statement::*, typ::Type}, validator::predefined::get_builtin_from_name}; +use crate::{common::{Loc, loc::LocBox}, parser::ast::{Ast, Program, Punctuation, Scope, TokenType, expr::*, literal::Literal, statement::*, typ::Type}, validator::predefined::get_builtin_from_name}; pub mod predefined; @@ -57,14 +57,14 @@ fn validate_stat(prog: &mut Program, stat: &mut LocBox, current_state 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(); + let val_t = validate_expr(prog, val)?.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 { + let Some(t) = validate_expr(prog, val)? else { lerror!(val.loc(), "Expected a type, go none"); bail!(""); }; @@ -79,7 +79,7 @@ fn validate_stat_let(prog: &mut Program, lt: &mut Let) -> anyhow::Result<()> { fn validate_ast(prog: &mut Program, ast: &mut Ast) -> anyhow::Result> { match ast { Ast::Expr(expr) => { - validate_expr(prog, expr.inner_mut()) + validate_expr(prog, expr) } Ast::Statement(stat) => { validate_stat(prog, stat, CurrentState::InFunc)?; @@ -89,12 +89,23 @@ fn validate_ast(prog: &mut Program, ast: &mut Ast) -> anyhow::Result anyhow::Result> { - match expr { +pub fn validate_expr(prog: &mut Program, expr: &mut LocBox) -> anyhow::Result> { + match expr.inner_mut() { + Expr::Self_ { strct } => { + if let Some(name) = &prog.curr_struct { + *strct = Some(name.clone()); + let mut t = Type::Owned(name.clone()); + t.convert_owned_to_real_type(prog); + Ok(Some(t)) + } else { + lerror!(expr.loc(), ""); + bail!("") + } + } Expr::Break | Expr::Continue => Ok(None), Expr::Return(ret) => { if let Some(expr) = &mut**ret { - validate_expr(prog, expr.inner_mut()) + validate_expr(prog, expr) } else { Ok(None) } @@ -107,7 +118,7 @@ pub fn validate_expr(prog: &mut Program, expr: &mut Expr) -> anyhow::Result anyhow::Result { - validate_expr(prog, ifs.test.inner_mut())?; + validate_expr(prog, &mut ifs.test)?; for item in ifs.body.0.iter_mut() { validate_ast(prog, item)?; } @@ -132,7 +143,7 @@ pub fn validate_expr(prog: &mut Program, expr: &mut Expr) -> anyhow::Result validate_expr(prog, group.inner_mut()), + Expr::Group(group) => validate_expr(prog, group), Expr::Call { path, params } => { let loc = path.loc().clone(); let Expr::Path(path) = path.inner_mut() else { @@ -145,14 +156,16 @@ pub fn validate_expr(prog: &mut Program, expr: &mut Expr) -> anyhow::Result { 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(); + let mut ft = func.inner().params[i].1.inner().clone(); + let t = validate_expr(prog, param)?.clone(); match t { - Some(t) => { + Some(mut t) => { + t.convert_owned_to_real_type(prog); + ft.convert_owned_to_real_type(prog); let t = t.get_variable_type(prog)?; let ft = ft.get_variable_type(prog)?; if t != ft { - lerror!(param.loc(), "expected {ft:?}, got {t:?}"); + lerror!(param.loc(), "expected {ft}, got {t}"); bail!("owo") } } @@ -181,7 +194,7 @@ pub fn validate_expr(prog: &mut Program, expr: &mut Expr) -> anyhow::Result { 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(); + let t = validate_expr(prog, param)?.clone(); match t { Some(t) => { if t.get_absolute_value(prog)? != ft.get_absolute_value(prog)? { @@ -214,14 +227,14 @@ pub fn validate_expr(prog: &mut Program, expr: &mut Expr) -> anyhow::Result { + Expr::MethodCall { left, strct, 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())?; + var_t = validate_expr(prog, &mut left.clone().unwrap())?; + let name = validate_expr(prog, right)?; match name.unwrap() { Type::Owned(name) => method_name = name, _ => unreachable!() @@ -233,12 +246,12 @@ pub fn validate_expr(prog: &mut Program, expr: &mut Expr) -> anyhow::Result anyhow::Result { let _ = validate_ast(prog, init)?; - let _ = validate_expr(prog, test.inner_mut())?; - let _ = validate_expr(prog, on_loop.inner_mut())?; + let _ = validate_expr(prog, test)?; + let _ = validate_expr(prog, on_loop)?; for item in body.0.iter_mut() { let _ = validate_ast(prog, item)?; } Ok(None) }, Expr::Cast { left, right } => { - validate_expr(prog, left.inner_mut())?; + validate_expr(prog, left)?; Ok(Some(right.inner_mut().clone())) } Expr::Literal(id, lit) => { @@ -273,15 +286,32 @@ pub fn validate_expr(prog: &mut Program, expr: &mut Expr) -> anyhow::Result { + for item in items { + let typ = validate_expr(prog, item)?; + if item_size.is_none() { + *item_size = Some(typ.unwrap().get_variable_type(prog)?.size_of(prog)?); + } + } + }, + Literal::ArrayRepeat { val, item_size, count: _ } => { + let typ = validate_expr(prog, val)?; + *item_size = Some(typ.unwrap().size_of(prog)?); + } + _ => (), + } 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_mut())?.unwrap().get_absolute_value(prog)?; + let t = validate_expr(prog, right)?.unwrap().get_absolute_value(prog)?; if !t.is_bool(prog) { lerror!(right.loc(), "Expected bool, got {t}"); } @@ -289,7 +319,7 @@ pub fn validate_expr(prog: &mut Program, expr: &mut Expr) -> anyhow::Result { - let t = validate_expr(prog, right.inner_mut())?.unwrap().get_absolute_value(prog)?; + let t = validate_expr(prog, right)?.unwrap().get_absolute_value(prog)?; if !t.is_numeric(prog) { lerror!(right.loc(), "Expected number, got {t}"); } @@ -297,11 +327,11 @@ pub fn validate_expr(prog: &mut Program, expr: &mut Expr) -> anyhow::Result { - let t = validate_expr(prog, right.inner_mut())?.unwrap().get_absolute_value(prog)?; + let t = validate_expr(prog, right)?.unwrap().get_absolute_value(prog)?; Ok(Some(Type::Ref { inner: Box::new(t), mutable: false })) } Punctuation::Star => { - let t = validate_expr(prog, right.inner_mut())?.unwrap().get_absolute_value(prog)?; + let t = validate_expr(prog, right)?.unwrap().get_absolute_value(prog)?; if !t.is_ptr(prog) { lerror!(right.loc(), "Expected pointer, got {t}"); } @@ -328,8 +358,8 @@ pub fn validate_expr(prog: &mut Program, expr: &mut Expr) -> anyhow::Result { let t1_s; let t2_s; - 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)?; + let t1 = validate_expr(prog, left)?.unwrap().get_absolute_value(prog)?; + let t2 = validate_expr(prog, right)?.unwrap().get_absolute_value(prog)?; if !(t1.is_numeric(prog) || t1.is_ptr(prog)) { lerror!(right.loc(), "Expected number, got {t1}"); } @@ -359,8 +389,8 @@ pub fn validate_expr(prog: &mut Program, expr: &mut Expr) -> anyhow::Result { - 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)?; + let t1 = validate_expr(prog, left)?.unwrap().get_absolute_value(prog)?; + let t2 = validate_expr(prog, right)?.unwrap().get_absolute_value(prog)?; if !(t1.is_numeric(prog) || t1.is_ptr(prog)) { lerror!(right.loc(), "Expected number or pointer, got {t1}"); } @@ -381,9 +411,9 @@ pub fn validate_expr(prog: &mut Program, expr: &mut Expr) -> anyhow::Result { - let var = validate_expr(prog, left.inner_mut())?.unwrap(); + let var = validate_expr(prog, left)?.unwrap(); let var_t = var.get_absolute_value(prog)?; - let val_t = validate_expr(prog, right.inner_mut())?.unwrap().get_absolute_value(prog)?; + let val_t = validate_expr(prog, right)?.unwrap().get_absolute_value(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}"); @@ -394,9 +424,9 @@ pub fn validate_expr(prog: &mut Program, expr: &mut Expr) -> anyhow::Result { - let var = validate_expr(prog, left.inner_mut())?.unwrap(); + let var = validate_expr(prog, left)?.unwrap(); let var_t = var.get_absolute_value(prog)?; - let val_t = validate_expr(prog, right.inner_mut())?.unwrap().get_absolute_value(prog)?; + let val_t = validate_expr(prog, right)?.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}"); @@ -409,7 +439,7 @@ pub fn validate_expr(prog: &mut Program, expr: &mut Expr) -> anyhow::Result { - let left = validate_expr(prog, name.inner_mut())?; + let left = validate_expr(prog, name)?; let Some(left) = left else { lerror!(name.loc(), "expected value, got nothing, cannot index nothing"); bail!("") @@ -451,22 +481,61 @@ pub fn validate_expr(prog: &mut Program, expr: &mut Expr) -> anyhow::Result { - let left = validate_expr(prog, left.clone().unwrap().inner_mut())?; - let right = validate_expr(prog, right.clone().inner_mut())?.unwrap(); + Expr::PtrFieldAccess { left, right, offset, l_typ, r_typ } => { + let left = validate_expr(prog, &mut left.clone().unwrap())?; + let right = validate_expr(prog, &mut right.clone())?.unwrap(); let Type::Owned(right) = right else { panic!() }; - match left.unwrap().get_absolute_value(prog)? { + let mut left = left.unwrap(); + left.convert_owned_to_real_type(prog); + *l_typ = Some(Box::new(left.clone())); + match left { + Type::Ref { inner, mutable: _ } => { + match *inner { + Type::Owned(name) => { + if let Some(strct) = prog.structs.get(&name) { + for field in strct.inner().fields.iter() { + if field.0 == right { + *r_typ = Some(Box::new(field.1.inner().clone())); + *offset = strct.inner().clone().get_offset_of(prog, &right)?; + info!("Offset {right:?} = {offset}"); + return Ok(Some(field.1.inner().clone())); + } + } + } else { + panic!("couldnt find struct {name}"); + } + } + v => panic!("{v:?}"), + } + } + v => panic!("{v:?}"), + } + + Ok(None) + }, + Expr::FieldAccess { left, right, offset, l_typ, r_typ } => { + let left = validate_expr(prog, &mut left.clone().unwrap())?; + let right = validate_expr(prog, &mut right.clone())?.unwrap(); + let Type::Owned(right) = right else { + panic!() + }; + let mut left = left.unwrap(); + left.convert_owned_to_real_type(prog); + *l_typ = Some(Box::new(left.clone())); + match left { Type::Owned(name) => { if let Some(strct) = prog.structs.get(&name) { for field in strct.inner().fields.iter() { if field.0 == right { + *r_typ = Some(Box::new(field.1.inner().clone())); *offset = strct.inner().clone().get_offset_of(prog, &right)?; return Ok(Some(field.1.inner().clone())); } } + } else { + panic!("couldnt find struct {name}"); } } v => panic!("{v:?}"), @@ -475,7 +544,7 @@ pub fn validate_expr(prog: &mut Program, expr: &mut Expr) -> anyhow::Result { - let _ = validate_expr(prog, test.inner_mut())?; + let _ = validate_expr(prog, test.as_mut())?; for item in body.0.iter_mut() { let _ = validate_ast(prog, item)?; } @@ -494,6 +563,8 @@ pub fn validate_expr(prog: &mut Program, expr: &mut Expr) -> anyhow::Result anyhow::Result<()> { prog.scope = Some(Scope::default()); + prog.curr_struct = func.struct_name.clone(); + for param in &func.params { let t = validate_type(prog, ¶m.1)?; prog.curr_fn_args.insert(param.0.clone(), LocBox::new(&Loc::default(), t.clone())); @@ -504,6 +575,7 @@ fn validate_fn(prog: &mut Program, func: &mut Function) -> anyhow::Result<()> { } } + prog.curr_struct = None; Ok(()) } @@ -600,9 +672,9 @@ fn check_that_types_exist_for_items(prog: &mut Program, items: &Vec) -> any fn validate_type(prog: &mut Program, typ: &LocBox) -> anyhow::Result { fn f(prog: &mut Program, typ: &Type, loc: &Loc) -> anyhow::Result { match typ { - Type::SizedArray { inner, .. } | - Type::UnsizedArray { inner, .. } | - Type::Ref { inner, .. } => f(prog, inner, loc), + Type::SizedArray { .. } | + Type::UnsizedArray { .. } | + Type::Ref { .. } => Ok(typ.clone()), Type::Owned(ident) => { if let Some(builtin) = get_builtin_from_name(&ident.0) { Ok(builtin) diff --git a/src/validator/predefined.rs b/src/validator/predefined.rs index 10324fa..d5728dc 100644 --- a/src/validator/predefined.rs +++ b/src/validator/predefined.rs @@ -10,43 +10,130 @@ pub const SIZE: usize = 8; #[cfg(target_arch="x86")] pub const SIZE: usize = 4; +pub struct BuiltinType; + +impl BuiltinType { + pub fn void() -> Type { + Type::new_builtin("void", 0, false) + } + pub fn usize() -> Type { + Type::new_builtin("usize", SIZE as u8, false) + } + pub fn isize() -> Type { + Type::new_builtin("isize", SIZE as u8, true) + } + pub fn u8() -> Type { + Type::new_builtin("u8", 1, false) + } + pub fn u16() -> Type { + Type::new_builtin("u16", 2, false) + } + pub fn u32() -> Type { + Type::new_builtin("u32", 4, false) + } + pub fn u64() -> Type { + Type::new_builtin("u64", 8, false) + } + pub fn i8() -> Type { + Type::new_builtin("i8", 1, true) + } + pub fn i16() -> Type { + Type::new_builtin("i16", 2, true) + } + pub fn i32() -> Type { + Type::new_builtin("i32", 4, true) + } + pub fn i64() -> Type { + Type::new_builtin("i64", 8, true) + } + pub fn bool() -> Type { + Type::new_builtin("bool", 1, true) + } + pub fn char() -> Type { + Type::new_builtin("char", 1, true) + } +} lazy_static!( - pub static ref TYPES_RAW: HashMap<&'static str, (usize, bool)> = [ - ("void", (0, false)), - ("usize", (SIZE, false)), - ("isize", (SIZE, true)), - ("u8", (1, false)), - ("u16", (2, false)), - ("u32", (4, false)), - ("u64", (8, false)), - ("i8", (1, true)), - ("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)> = [ - ("__INTERNAL_syscall", (vec![ - ("arg_count", "u8"), - ("sc_num", "u8"), - ("args", "&[&void]") - ], "usize")), + pub static ref TYPES_RAW: Vec = [ + BuiltinType::void(), + BuiltinType::usize(), + BuiltinType::isize(), + BuiltinType::u8(), + BuiltinType::u16(), + BuiltinType::u32(), + BuiltinType::u64(), + BuiltinType::i8(), + BuiltinType::i16(), + BuiltinType::i32(), + BuiltinType::i64(), + BuiltinType::bool(), + BuiltinType::char() + ].to_vec(); + pub static ref FUNCTIONS: HashMap<&'static str, (Vec<(&'static str, Type)>, Type)> = [ + ("__INTERNAL_syscall0", (vec![ + ("sc_num", BuiltinType::usize()), + ], BuiltinType::usize())), + ("__INTERNAL_syscall1", (vec![ + ("sc_num", BuiltinType::usize()), + ("arg0", BuiltinType::void().as_ref()), + ], BuiltinType::usize())), + ("__INTERNAL_syscall2", (vec![ + ("sc_num", BuiltinType::usize()), + ("arg0", BuiltinType::void().as_ref()), + ("arg1", BuiltinType::void().as_ref()), + ], BuiltinType::usize())), + ("__INTERNAL_syscall3", (vec![ + ("sc_num", BuiltinType::usize()), + ("arg0", BuiltinType::void().as_ref()), + ("arg1", BuiltinType::void().as_ref()), + ("arg2", BuiltinType::void().as_ref()), + ], BuiltinType::usize())), + ("__INTERNAL_syscall4", (vec![ + ("sc_num", BuiltinType::usize()), + ("arg0", BuiltinType::void().as_ref()), + ("arg1", BuiltinType::void().as_ref()), + ("arg2", BuiltinType::void().as_ref()), + ("arg3", BuiltinType::void().as_ref()), + ], BuiltinType::usize())), + ("__INTERNAL_syscall5", (vec![ + ("sc_num", BuiltinType::usize()), + ("arg0", BuiltinType::void().as_ref()), + ("arg1", BuiltinType::void().as_ref()), + ("arg2", BuiltinType::void().as_ref()), + ("arg3", BuiltinType::void().as_ref()), + ("arg4", BuiltinType::void().as_ref()), + ], BuiltinType::usize())), + ("__INTERNAL_syscall6", (vec![ + ("sc_num", BuiltinType::usize()), + ("arg0", BuiltinType::void().as_ref()), + ("arg1", BuiltinType::void().as_ref()), + ("arg2", BuiltinType::void().as_ref()), + ("arg3", BuiltinType::void().as_ref()), + ("arg4", BuiltinType::void().as_ref()), + ("arg5", BuiltinType::void().as_ref()), + ], BuiltinType::usize())), ].into(); ); -pub fn get_builtin_from_name(name: &str) -> Option { - 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 get_builtin_from_name(type_name: &str) -> Option { + for t in TYPES_RAW.iter() { + match t { + Type::Builtin { name, .. } if name.as_str() == type_name => { + return Some(t.clone()); + } + Type::Builtin { .. } => (), + _ => unreachable!() + } } + None } pub fn load_builtin(prog: &mut Program) { let loc = Loc::new("(internal)", 0, 0); - for (name, (size, signed)) in TYPES_RAW.iter() { + for t in TYPES_RAW.iter() { + let Type::Builtin { name, size, signed } = t else {unreachable!()}; prog.types.insert( - Ident(name.to_string()), + Ident(name.clone()), LocBox::new(&loc, Type::Builtin{ name: name.to_string(), size: *size as u8, signed: *signed }) ); } @@ -54,15 +141,12 @@ pub fn load_builtin(prog: &mut Program) { for (name, (args, ret_typ)) in FUNCTIONS.iter() { let mut params = Vec::new(); let mut ret_type = None; - if ret_typ.len() > 0 { - let mut ret_t_tokens = crate::tokeniser::tokenise(&ret_typ, "(internal)").unwrap(); - let typ = parse_type(&mut ret_t_tokens).unwrap(); - ret_type = Some(LocBox::new(&Loc::default(), typ.inner().clone())); + if !ret_typ.is_void() { + + ret_type = Some(LocBox::new(&Loc::default(), ret_typ.clone())); } for (name, typ) in args { - let mut tokens = crate::tokeniser::tokenise(&typ, "(internal)").unwrap(); - let typ = parse_type(&mut tokens).unwrap(); - params.push((Ident(name.to_string()), LocBox::new(&Loc::new("(internal)", 0, 0), typ.inner().clone()))); + params.push((Ident(name.to_string()), LocBox::new(&Loc::new("(internal)", 0, 0), typ.clone()))); } let f = Function { diff --git a/std/core.mcl b/std/core.mcl new file mode 100644 index 0000000..c01e35d --- /dev/null +++ b/std/core.mcl @@ -0,0 +1,2 @@ +include "std/str.mcl"; +include "std/io/mod.mcl"; diff --git a/std/io/mod.mcl b/std/io/mod.mcl new file mode 100644 index 0000000..94a4219 --- /dev/null +++ b/std/io/mod.mcl @@ -0,0 +1,12 @@ + +fn write_str(fd: usize, s: &str) -> usize { + return __INTERNAL_syscall3(1, fd as &void, s->inner as &void, s->len as &void); +} + +fn puts(s: &str) { + write_str(1, s); +} + +fn eputs(s: &str) { + write_str(2, s); +} diff --git a/std/lib/beaker.mcl b/std/lib/beaker.mcl new file mode 100644 index 0000000..7ccf69b --- /dev/null +++ b/std/lib/beaker.mcl @@ -0,0 +1,107 @@ + + +const MAX_CONTEXT_VARS: usize = 32; +const MAX_KEY_LEN: usize = 64; +const MAX_VALUE_LEN: usize = 256; +const MAX_PATH_LEN: usize = 256; +const MAX_HANDLERS: usize = 32; +const BUFFER_SIZE: usize = 4096; +const MAX_URL_PARAMS: usize = 16; +const MAX_COOKIES: usize = 10; +const MAX_OUTER_ARRAY_ITEMS: usize = 100; +const MAX_INNER_ARRAY_ITEMS: usize = 200; + +const TEMPLATES_DIR: &str = "templates/"; +const STATIC_DIR: &str = "static/"; +/* +enum ContextType { + CONTEXT_TYPE_STRING, + CONTEXT_TYPE_STRING_ARRAY, + CONTEXT_TYPE_STRING_2D_ARRAY, +}; +*/ +type ContextType = i32; +struct CV_array_data { + values: &&char, + count: i32, +} + +struct CV_2d_array_data { + values: &&&char, + count: i32, +} + + +struct ContextVarStr { + key: char[MAX_KEY_LEN], + typ: ContextType, + value: char[MAX_VALUE_LEN] +} + +struct ContextVarArr { + key: char[MAX_KEY_LEN], + typ: ContextType, + value: CV_array_data, +} + +struct ContextVar2dArr { + key: char[MAX_KEY_LEN], + typ: ContextType, + value: CV_2d_array_data, +} + +struct ContextVar { + key: char[MAX_KEY_LEN], + typ: ContextType, + value: char[MAX_VALUE_LEN] +} + +struct TemplateContext { + vars: ContextVar[MAX_CONTEXT_VARS], + count: i32, +} + +struct UrlParam { + key: char[MAX_KEY_LEN], + value: char[MAX_VALUE_LEN], +} + +struct UrlParams { + params: UrlParam[MAX_URL_PARAMS], + count: i32 +} +struct Cookie { + name: char[MAX_KEY_LEN], + value: char[MAX_VALUE_LEN], + expires: char[MAX_VALUE_LEN], + path: char[MAX_KEY_LEN], + http_only: bool, + secure: bool +} + +type RequestHandler = fn(params: &UrlParams); + +struct RouteHandler { + path: char[MAX_PATH_LEN], + handler: RequestHandler +} + +extern fn new_context() -> TemplateContext; +extern fn context_set(ctx: &mut TemplateContext, key: &cstr, value: &cstr); +extern fn context_set_string_array(ctx: &mut TemplateContext, key: &cstr, values: &cstr, count: i32); +extern fn context_set_array_of_arrays(ctx: &mut TemplateContext, key: &cstr, values: &cstr[][], outer_count: i32, inner_count: i32); +extern fn free_context(ctx: &mut TemplateContext); +extern fn render_template(template_file: &cstr, ctx: &mut TemplateContext) -> &cstr; + +extern fn send_response(html: &cstr); +extern fn send_redirect(location: &cstr); +extern fn set_cookie(name: &cstr, value: &cstr, expires: &cstr, path: &cstr, http_only: bool, secure: bool); +extern fn get_cookie(name: &cstr) -> &cstr; + +extern fn set_handler(path: &cstr, handler: RequestHandler); +extern fn parse_request_url(request_buffer: &cstr, params: &UrlParams) -> &cstr; +extern fn get_mime_type(file_path: &cstr) -> &cstr; +extern fn serve_static_file(request_path_relative_to_static: &cstr) -> bool; + +extern fn beaker_run(ip: &cstr, port: i32) -> i32; + diff --git a/std/str.mcl b/std/str.mcl new file mode 100644 index 0000000..785dd51 --- /dev/null +++ b/std/str.mcl @@ -0,0 +1,14 @@ +type cstr = [u8]; + + +struct str { + len: usize, + inner: &cstr +} + +fn str.len(&self) -> usize { + return self.len; +} + + + diff --git a/test b/test index be02ec6..25f1056 100755 Binary files a/test and b/test differ diff --git a/test.mcl b/test.mcl index 821c6d8..3fe1a78 100644 --- a/test.mcl +++ b/test.mcl @@ -7,9 +7,9 @@ struct Foo { b: &str } -fn Foo.new(a: usize, b: &str) -> &Foo { +fn Foo.new(a1: usize, b: &str) -> &Foo { return &Foo { - a: a, + a: a1, b: b }; } @@ -31,7 +31,7 @@ fn main() -> i32 { } for (let i = 0; i < 10; i += 1) { - print("nyaaa"); + puts("nyaaa"); if (i > 7) { break; } else { diff --git a/test.o b/test.o index 8afc65a..76a588f 100644 Binary files a/test.o and b/test.o differ diff --git a/test2.mcl b/test2.mcl new file mode 100644 index 0000000..b01f40e --- /dev/null +++ b/test2.mcl @@ -0,0 +1,6 @@ +// include "std/core.mcl"; +include "beaker.mcl"; + +fn main() -> i32 { + //puts("owo\n"); +} diff --git a/tests/mod.rs b/tests/mod.rs new file mode 100644 index 0000000..b93e263 --- /dev/null +++ b/tests/mod.rs @@ -0,0 +1 @@ +mod parser; diff --git a/tests/parser/expr.rs b/tests/parser/expr.rs new file mode 100644 index 0000000..b28b04f --- /dev/null +++ b/tests/parser/expr.rs @@ -0,0 +1,3 @@ + + + diff --git a/tests/parser/mod.rs b/tests/parser/mod.rs new file mode 100644 index 0000000..2d9774c --- /dev/null +++ b/tests/parser/mod.rs @@ -0,0 +1,3 @@ +mod expr; +mod stat; +mod typ; diff --git a/tests/parser/stat.rs b/tests/parser/stat.rs new file mode 100644 index 0000000..e69de29 diff --git a/tests/parser/typ.rs b/tests/parser/typ.rs new file mode 100644 index 0000000..56d123e --- /dev/null +++ b/tests/parser/typ.rs @@ -0,0 +1,190 @@ +use std::vec; + +use mclangc::{common::{Loc, loc::LocBox}, parser::{self, ast::{Ident, Keyword, Program, Punctuation, TokenType, statement::{Enum, Struct}, typ::Type}}, tokeniser::Token, validator::predefined::{BuiltinType, get_builtin_from_name, load_builtin}}; + + + +fn get_prog() -> Program { + let mut prog = Program::default(); + load_builtin(&mut prog); + let loc = Loc::default(); + prog.structs.insert(Ident::new("MyStruct"), LocBox::new(&loc, Struct { + name: Ident::new("MyStruct"), + fields: vec![ + (Ident::new("foo"), LocBox::new(&loc, BuiltinType::usize())), + (Ident::new("bar"), LocBox::new(&loc, BuiltinType::bool())), + (Ident::new("baz"), LocBox::new(&loc, Type::Owned(Ident::new("str")).as_ref())), + ] + })); + prog.enums.insert(Ident::new("MyEnum"), LocBox::new(&loc, Enum { + name: Ident::new("MyEnum"), + fields: vec![], + })); + prog +} + +#[test] +fn parse_type_named_struct() { + let mut tokens = vec![ + Token::new_test(TokenType::Ident(Ident::new("MyStruct"))) + ]; + let ret = parser::typ::parse_type(&mut tokens); + assert!(ret.is_ok()); + assert_eq!(ret.unwrap(), LocBox::new(&Loc::default(), Type::Owned(Ident::new("MyStruct")))) +} + +#[test] +fn parse_type_named_enum() { + let mut tokens = vec![ + Token::new_test(TokenType::Ident(Ident::new("MyEnum"))) + ]; + let ret = parser::typ::parse_type(&mut tokens); + assert!(ret.is_ok()); + assert_eq!(ret.unwrap(), LocBox::new(&Loc::default(), Type::Owned(Ident::new("MyEnum")))) +} + +#[test] +fn parse_type_ref() { + let mut tokens = vec![ + Token::new_test(TokenType::Punct(Punctuation::Ampersand)), + Token::new_test(TokenType::Ident(Ident::new("MyStruct"))) + ]; + tokens.reverse(); + let ret = parser::typ::parse_type(&mut tokens); + assert!(ret.is_ok()); + assert_eq!(ret.unwrap(), LocBox::new(&Loc::default(), Type::Owned(Ident::new("MyStruct")).as_ref())) +} + +#[test] +fn parse_type_ref2() { + let mut tokens = vec![ + Token::new_test(TokenType::Punct(Punctuation::Ampersand)), + Token::new_test(TokenType::Punct(Punctuation::Ampersand)), + Token::new_test(TokenType::Ident(Ident::new("MyStruct"))) + ]; + tokens.reverse(); + let ret = parser::typ::parse_type(&mut tokens); + assert!(ret.is_ok()); + assert_eq!(ret.unwrap(), LocBox::new(&Loc::default(), Type::Owned(Ident::new("MyStruct")).as_ref().as_ref())) +} + +#[test] +fn parse_type_ref3() { + let mut tokens = vec![ + Token::new_test(TokenType::Punct(Punctuation::Ampersand)), + Token::new_test(TokenType::Punct(Punctuation::Ampersand)), + Token::new_test(TokenType::Punct(Punctuation::Ampersand)), + Token::new_test(TokenType::Ident(Ident::new("MyStruct"))) + ]; + tokens.reverse(); + let ret = parser::typ::parse_type(&mut tokens); + assert!(ret.is_ok()); + assert_eq!(ret.unwrap(), LocBox::new(&Loc::default(), Type::Owned(Ident::new("MyStruct")).as_ref().as_ref().as_ref())) +} + +#[test] +fn parse_type_mut_ref() { + let mut tokens = vec![ + Token::new_test(TokenType::Punct(Punctuation::Ampersand)), + Token::new_test(TokenType::Keyword(Keyword::Mut)), + Token::new_test(TokenType::Ident(Ident::new("MyStruct"))) + ]; + tokens.reverse(); + let ret = parser::typ::parse_type(&mut tokens); + assert!(ret.is_ok()); + assert_eq!(ret.unwrap(), LocBox::new(&Loc::default(), Type::Owned(Ident::new("MyStruct")).as_ref_mut())) +} + +#[test] +fn parse_type_mut_ref2() { + let mut tokens = vec![ + Token::new_test(TokenType::Punct(Punctuation::Ampersand)), + Token::new_test(TokenType::Keyword(Keyword::Mut)), + Token::new_test(TokenType::Punct(Punctuation::Ampersand)), + Token::new_test(TokenType::Keyword(Keyword::Mut)), + Token::new_test(TokenType::Ident(Ident::new("MyStruct"))) + ]; + tokens.reverse(); + let ret = parser::typ::parse_type(&mut tokens); + assert!(ret.is_ok()); + assert_eq!(ret.unwrap(), LocBox::new(&Loc::default(), Type::Owned(Ident::new("MyStruct")).as_ref_mut().as_ref_mut())) +} + +#[test] +fn parse_type_mut_ref3() { + let mut tokens = vec![ + Token::new_test(TokenType::Punct(Punctuation::Ampersand)), + Token::new_test(TokenType::Keyword(Keyword::Mut)), + Token::new_test(TokenType::Punct(Punctuation::Ampersand)), + Token::new_test(TokenType::Keyword(Keyword::Mut)), + Token::new_test(TokenType::Punct(Punctuation::Ampersand)), + Token::new_test(TokenType::Keyword(Keyword::Mut)), + Token::new_test(TokenType::Ident(Ident::new("MyStruct"))) + ]; + tokens.reverse(); + let ret = parser::typ::parse_type(&mut tokens); + assert!(ret.is_ok()); + assert_eq!(ret.unwrap(), LocBox::new(&Loc::default(), Type::Owned(Ident::new("MyStruct")).as_ref_mut().as_ref_mut().as_ref_mut())) +} + +fn test_builtin(s: &str) { + let mut tokens = vec![ + Token::new_test(TokenType::Ident(Ident::new(s))) + ]; + let ret = parser::typ::parse_type(&mut tokens); + assert!(ret.is_ok()); + assert_eq!(ret.unwrap(), LocBox::new(&Loc::default(), get_builtin_from_name(s).unwrap())) +} + +#[test] +fn parse_type_builtin_usize() { + test_builtin("usize"); +} +#[test] +fn parse_type_builtin_isize() { + test_builtin("isize"); +} +#[test] +fn parse_type_builtin_u8() { + test_builtin("u8"); +} +#[test] +fn parse_type_builtin_i8() { + test_builtin("i8"); +} +#[test] +fn parse_type_builtin_u16() { + test_builtin("u16"); +} +#[test] +fn parse_type_builtin_i16() { + test_builtin("i16"); +} +#[test] +fn parse_type_builtin_u32() { + test_builtin("u32"); +} +#[test] +fn parse_type_builtin_i32() { + test_builtin("i32"); +} +#[test] +fn parse_type_builtin_u64() { + test_builtin("u64"); +} +#[test] +fn parse_type_builtin_i64() { + test_builtin("i64"); +} +#[test] +fn parse_type_builtin_void() { + test_builtin("void"); +} +#[test] +fn parse_type_builtin_char() { + test_builtin("char"); +} +#[test] +fn parse_type_builtin_bool() { + test_builtin("bool"); +} diff --git a/tests/tokeniser/comments.exp b/tests/tokeniser/comments.exp deleted file mode 100644 index 0637a08..0000000 --- a/tests/tokeniser/comments.exp +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file