From 4b61adea5db611cf46ec8161f63e44c68919fc74 Mon Sep 17 00:00:00 2001 From: MCorange Date: Tue, 3 Feb 2026 13:20:23 +0200 Subject: [PATCH] Fix bugs, add propper tests --- include/std.mcl | 7 - libbeaker.a | Bin 0 -> 57668 bytes {tests => old_tests}/parser/enumerations.exp | 0 {tests => old_tests}/parser/enumerations.mcl | 0 {tests => old_tests}/parser/expressions.exp | 0 {tests => old_tests}/parser/expressions.mcl | 0 {tests => old_tests}/parser/functions.exp | 0 {tests => old_tests}/parser/functions.mcl | 0 {tests => old_tests}/parser/if-statements.exp | 0 {tests => old_tests}/parser/if-statements.mcl | 0 {tests => old_tests}/parser/loops.exp | 0 {tests => old_tests}/parser/loops.mcl | 0 {tests => old_tests}/parser/structs.exp | 0 {tests => old_tests}/parser/structs.mcl | 0 old_tests/tokeniser/comments.exp | 1 + {tests => old_tests}/tokeniser/comments.mcl | 0 {tests => old_tests}/tokeniser/delimiters.exp | 2 +- {tests => old_tests}/tokeniser/delimiters.mcl | 0 {tests => old_tests}/tokeniser/keywords.exp | 0 {tests => old_tests}/tokeniser/keywords.mcl | 0 {tests => old_tests}/tokeniser/literals.exp | 0 {tests => old_tests}/tokeniser/literals.mcl | 0 .../tokeniser/punctuation.exp | 0 .../tokeniser/punctuation.mcl | 0 src/bin/{test => tester}/logger.rs | 0 src/bin/{test => tester}/main.rs | 2 +- src/cli.rs | 7 +- src/main.rs | 6 +- src/parser/ast/expr.rs | 18 +- src/parser/ast/literal.rs | 19 +- src/parser/ast/mod.rs | 6 +- src/parser/ast/statement.rs | 92 +++++++-- src/parser/ast/typ.rs | 81 +++++++- src/parser/expr.rs | 130 ++++++------ src/parser/mod.rs | 36 ++-- src/parser/stat.rs | 77 ++++--- src/parser/typ.rs | 10 +- src/targets/mod.rs | 4 +- src/targets/x86_64/asmgen/linux/mod.rs | 121 +++++++++-- src/targets/x86_64/asmgen/linux/runtime.s | 91 ++++++--- src/tokeniser/mod.rs | 10 + src/tokeniser/tokentype.rs | 5 +- src/validator/mod.rs | 166 ++++++++++----- src/validator/predefined.rs | 152 ++++++++++---- std/core.mcl | 2 + std/io/mod.mcl | 12 ++ std/lib/beaker.mcl | 107 ++++++++++ std/str.mcl | 14 ++ test | Bin 10016 -> 10096 bytes test.mcl | 6 +- test.o | Bin 2768 -> 2960 bytes test2.mcl | 6 + tests/mod.rs | 1 + tests/parser/expr.rs | 3 + tests/parser/mod.rs | 3 + tests/parser/stat.rs | 0 tests/parser/typ.rs | 190 ++++++++++++++++++ tests/tokeniser/comments.exp | 1 - 58 files changed, 1103 insertions(+), 285 deletions(-) delete mode 100644 include/std.mcl create mode 100644 libbeaker.a rename {tests => old_tests}/parser/enumerations.exp (100%) rename {tests => old_tests}/parser/enumerations.mcl (100%) rename {tests => old_tests}/parser/expressions.exp (100%) rename {tests => old_tests}/parser/expressions.mcl (100%) rename {tests => old_tests}/parser/functions.exp (100%) rename {tests => old_tests}/parser/functions.mcl (100%) rename {tests => old_tests}/parser/if-statements.exp (100%) rename {tests => old_tests}/parser/if-statements.mcl (100%) rename {tests => old_tests}/parser/loops.exp (100%) rename {tests => old_tests}/parser/loops.mcl (100%) rename {tests => old_tests}/parser/structs.exp (100%) rename {tests => old_tests}/parser/structs.mcl (100%) create mode 100644 old_tests/tokeniser/comments.exp rename {tests => old_tests}/tokeniser/comments.mcl (100%) rename {tests => old_tests}/tokeniser/delimiters.exp (99%) rename {tests => old_tests}/tokeniser/delimiters.mcl (100%) rename {tests => old_tests}/tokeniser/keywords.exp (100%) rename {tests => old_tests}/tokeniser/keywords.mcl (100%) rename {tests => old_tests}/tokeniser/literals.exp (100%) rename {tests => old_tests}/tokeniser/literals.mcl (100%) rename {tests => old_tests}/tokeniser/punctuation.exp (100%) rename {tests => old_tests}/tokeniser/punctuation.mcl (100%) rename src/bin/{test => tester}/logger.rs (100%) rename src/bin/{test => tester}/main.rs (98%) create mode 100644 std/core.mcl create mode 100644 std/io/mod.mcl create mode 100644 std/lib/beaker.mcl create mode 100644 std/str.mcl create mode 100644 test2.mcl create mode 100644 tests/mod.rs create mode 100644 tests/parser/expr.rs create mode 100644 tests/parser/mod.rs create mode 100644 tests/parser/stat.rs create mode 100644 tests/parser/typ.rs delete mode 100644 tests/tokeniser/comments.exp 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 0000000000000000000000000000000000000000..4d6d094e00d76d5950cd564b4d11b8665ad18db1 GIT binary patch literal 57668 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 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 be02ec62c0b1392372cc6742f84f816c4a224179..25f105601c11f85d4bbcc1d20d0c5ca68ff4ecdd 100755 GIT binary patch literal 10096 zcmeI2PiP}m9LHbMWR1d_tbeN_o7F7tVTtqRPi6+IM7J%IHQj={7hz#GZ3C^ON$E^k zd$Jlm3?T>}M9@{(lO7aLYw=XtvfX+RaTh!Z>M2lRT?8c;T=_CLkv$)JB(hN*VrirTQUR%eR6r^q z6_5%@1*8H}0jYpgKq_!oDiHK5!S!)P?aUTb=6Ge`7c!7~ zX+PEJju$eO;H3aGY4km{UH+dGE1d=L${=)O1=P2xd8c)(q=facp-etQ6sRAo? z+8Y_Cn?A%tuu;^f_dZMNq<^}f-N$$#2Y2gqz*d4yz&|ql&W8W$5c`?2Zu$zZ*y-K; z3mP0KTF0UX_nsOmy9{(Mx%UZ_&SL4~Y;U@;&i(hI0oALIpmL`66FI{=AU?7V>ife-HUb0>6y>V}XBx{BwbSeFwgS zd{@Z7&Utcw-h%st{D3?Y&0!$_9r;57&+>;QNgfsWN#vsfcaY}=K8O6cz~4lEQs9@6 z>jM7@`Ix|OARia_E#y^!KagajEQxq-24x_JIZu-FLjGfS;GaQZjwHziA)geV_3NHr z^oZ+L&YYWg<;;s!*IV^wYmLTjP_e3!r4`>JldV>vS-(h@mKT~nSzKw5#o9uXzZ9#~ zWj$l3-kig=>Mk@FqJTP_rMj)A+i10x!pu|Doms9mXXlmJAMUch)`pvCE(=UfPm{&j zhTB;1U8NCwc?;| zm8hYXG)>hl&48Y|9>=Jmo799tRkJKbp}H~DlIxeFM6xf;phlN8y2ix2aTDA%I zVVahrf-+RsObWm68P9V)zqafXw?0?%YlIZN)kVKH1J+*-?R>QI>#zHy7^X$f<^Q!$ zKp}ez@EI)DB>H=ab6oMf7K_0Zjdz6}A;)0B>PI3FJ?Hrl#B*C1KR8I^ xh#YLp>W;!sCd6bE?Y&^*y^%5V>C>T;7n-xP4qr#Wxn2D=oR52EI2qPr{omq*o~!@> literal 10016 zcmeI2&u<$=6vxMoT?`V$Edm)3;D9TNker?UIV&n;XcDcdqa0eKf{>PVY7tBRQL>9d zPFQjgtQK=964&+*;D&@E(L+S4M!iseT;RX~#KBUya45(JFf+SvY-dEcAWof4vTxq! z{o4I%l!HC*F4tDlsTAT@8ohv+x0bKOD7hna?PTl%BWMm)&@q&ab2HNrT~)wK><~O| zQ9c1|MwTtXM=+1uEAU9%@;ru*vAQC=(W_XA4Y%hL4{^)u081kkkP1izqyka_sen{K zDj*e*3P=T{0#bpyQh{((4Zo|*e|{5>@$dNCW%j$fjBj1O6)4r{`Q9iMoT^5Ct~W{t zPgbLI`QB(Qcz88BSLls0!TqbznPP904Kl0I*;Dh`JqPa&U#CJk;r`BPY8mSPns>s} zB_|9@x!T~NujXku%9N^M+KHA*xoY@Q>LC?;XxeQof8+Xt!GUb@h**<2>51;6&M% zS)Xv<8D!h>>gMpucszE(Oo^2`{oNc5t;8WZh4&eL!jhuwNeJZW6FY;YQob6}S=m1y zpiSS~4PKpLKQT7QrjvQYS6G8XMc+Wtg9lH|lzl=kP1iz{$~X~gYVtp>vnV> z%uC%P4E8qSpU$@DdEKqCM9!el%E5DgcGq%p_;(i zhYN_FKJWzoIPki_lj9316bbw}$p28_i@>=)u}g0{@S%|ZBJeu`Up<1q20V4V60i8} zP2dHAZvlTp;O_&k3;bi?ZwdVB5&To&10jDW=IQAfo}j;1b!K~A@FO!iNLP|UlRC_l;`Pw$ zw{i`;tZ?EqIu~KBy3J0L2h`at)$MlNR=0a8$vlJI`li=e-%uw0Y?tX;n{A@GEU>b+ zhT7{bx77?>tmwL8YX&w{-NKq?*%p}uiKXb4Vym`on1*Va#5N}}tPpG)3bC=KYMM?6 zR;Ptn!Mb8#lUl5+rea&lG^i7kPBS%4)rn@T3gU;)f+e+SUOQti6ca~*#;ooM`j<;E oDuBJ0+R1ES%zW^4;vBGto4EuR9jCE>s`ueM+cPt@Y$?|N4G^YuSpWb4 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 8afc65a0d1189a61ed44a223379a5dd9bd7c4f17..76a588f734ebd3af6f47a86ec20b8d58bb48e0d4 100644 GIT binary patch literal 2960 zcmbW3PiP}m9LHbNRD-fK;JOz7u&qSwLE^l5GnpCP)#$c$!lql?T?9cGX1kF_)1)-B zt_8tB6&ynGwkV1sco7l2D0@-5ZE5Ufk@cn^;weyJ@v<5Z#^0O#-Zc3&y*O>={od#I z{r!2vo5#F8TbxUbj4*YLuxHr8Oi{-22PWEimSUrQ^#7T%mi*mC!t;q9xJjBx6W!e~ zmlE1ZI@uGxLiC7ZdTdCnbgrQAbgb+dq#gDEU~F|j`8CFC*w`3&r{I@D)dY?wVWhoF z*KcxRa2+SfY5m7RL)R1q-V@!~5(Y?(G--Vu*s%DOdwcP!PpOfu(D<-Z2!G0tf4j@O z{0_f0EB`lV`QAHwfmUcf-RO)2(}iX|)#xOGlZEDmbfYsGoS1K3m}qp8!Lj+~naM_H zEJ)5b&rXkzZM%H4{Q;D5!`AgvFpiJ8>wl!&@KnZa%10<2v9(*=xIbbW$xIEnUSIH`erJ2K_Qi=eNBqgI%YCySgqTHu@G)4{O)G(GG(ett9|=l zNH8?$zWql@*nVRF)3}RP`$1WoZ(f(1z=bN~s$$q`cV*i3or!JvG<(;gUkxVfrPAbb zX{vU$7H_-inh)1f^oLtag)rQ*L(h*`lnqL61}uBo4}6xbFV%z9z`q36+H!Bi`D&@+ zqck!jeVpX5AsbAxKf8xL^8Je2A8?Njd2@SfI;?*riX36Zfeeg2h1@6nS>zuP{sQtA z;q%CUApAw-w+VjWsUBqO%<~H8F3z4m_gvAduhkd* zN@WPj76tR_fxjBCl`BD=&DCm|YUwIlSuIxswtS_+mi=-yx@C*pld0oLsd^c0-78ni z%AxnGbgx$RDz(~5PkDxWmsb7i;*u86`?DO_qCbi7q+@Pjfh{jqyh=InxMAtKW9x=v znzp4oIpM@U+u_{ewqaT};G8ZrJ@#?U=8ma>MCd{ow#{`rb{ck$n|e+N-LQoTISnKB zanrE41%bM-ZB65b*_V_XI^^M&=?HGvx^Q$e4zw-Jurx<^95V;WbGDO3o#5$ za4jeLQbGmI@7!4FVitLbK2mWN@qlr|np<4$HDN9i9v~gvAGTNCju| z&63|Cd7Qt2BjpXkHJpD*xQp{Ugy(Utj%1Zzeb+q{?eE^VhU{kw^##uxs`8{^FEv%Bfj^o`SI=b6v*eV%6~ zJ3E_?R%)x+OoqfQLtZ86D5iu|QWNY7$&OMdP{;gxIzZlK8&knVmlmJ&RZ zUje*<^f@#>Gb2_?Dj<9X>Ctq^_PbC<3!<-$a} ziwdG4d0uGnnq=Jd2jo@MgaE0LCa$jwHY@&{2Zcklc%D)t*NNl9aW(w8vhdw4I-!5j zpH}4m-U_|*$sMj$hfDo&hM%tvgM5FSVXjmSv)*vIl&^-b<-Nf{ zVgI-?lKh|~B3mu|vHJIKN+%K)y`j7zvW&L_)~(Tv$z&|P^WJyB&L zt{5JUCjW}GgM;F}T-V7K?;E(SBm?^^QTkizue0s@e)n2;)9>)bpwU=tH_j!RSw@*R zKIEi)#pgaL2U`K}aeqTt+wG`_aj((xL8?rppOp`ooNtc&F_|TqQ#<*jXKu!m7_B#6 zeH!zyGBc!>B4w3;`-r~)d;@U`e2BOM{4>OtfPag41^5W@HQ;|De)$ys9`LCnU6BBI z5q%W{;O`>-Iq(g{ZvuZG@vlzdyTEsl{y_1QC+BV8@j0W0;&Kl-KL4Y2W|MO&)<3Q4 zWyupUfPM-1ImF)r9^L2E$$@JrQr30g7UEw6XNcbhzKr-&Vq6gWc^&a&Sbmu|0$vVC zupMmrtybKZYX+$Y-0yKB1!T3`Ep-~#$kkr6!%6#t7HRv)ZRxhnTs!emjZxRqm`e@aFigg%o(58lnwmvz(Nj~m zHP_Knr^#$l%{C0(WQOJ1hH0i*gwqw6lyP1mxRql=1e5+`ixGRI=nvKezt*F3(1dT`_AlOcZ>RABr) z^f8z3W7(qTD0(+beRLiX@{97O{5cr^gSgy(vMs3nnd%>kFnJd7xbBOHzXbYa#MSFs a_})H+HxM@=&&P 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