Fix bugs, add propper tests
This commit is contained in:
@@ -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]);
|
||||
}
|
||||
BIN
libbeaker.a
Normal file
BIN
libbeaker.a
Normal file
Binary file not shown.
1
old_tests/tokeniser/comments.exp
Normal file
1
old_tests/tokeniser/comments.exp
Normal file
@@ -0,0 +1 @@
|
||||
[]
|
||||
@@ -59,4 +59,4 @@
|
||||
SquareL,
|
||||
),
|
||||
},
|
||||
]
|
||||
]
|
||||
@@ -133,7 +133,7 @@ fn test_parser(cf: &CollectedFiles, compile: bool) -> anyhow::Result<usize> {
|
||||
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}");
|
||||
@@ -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<String>,
|
||||
/// Output file
|
||||
#[arg(long, short, default_value="a.out")]
|
||||
pub output: String,
|
||||
|
||||
/// Linker args
|
||||
#[arg(long, short='L')]
|
||||
pub linker_args: Vec<String>,
|
||||
|
||||
/// All input files
|
||||
#[clap(num_args = 1..)]
|
||||
pub input: Vec<String>
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ pub enum Expr {
|
||||
},
|
||||
MethodCall {
|
||||
left: Box<LocBox<Expr>>,
|
||||
strct: Option<Ident>,
|
||||
params: CallParams,
|
||||
},
|
||||
|
||||
@@ -37,12 +38,16 @@ pub enum Expr {
|
||||
FieldAccess {
|
||||
left: Box<Option<LocBox<Expr>>>,
|
||||
right: Box<LocBox<Expr>>,
|
||||
offset: usize
|
||||
offset: usize,
|
||||
l_typ: Option<Box<Type>>,
|
||||
r_typ: Option<Box<Type>>,
|
||||
},
|
||||
PtrFieldAccess {
|
||||
left: Box<Option<LocBox<Expr>>>,
|
||||
right: Box<LocBox<Expr>>,
|
||||
offset: usize
|
||||
offset: usize,
|
||||
l_typ: Option<Box<Type>>,
|
||||
r_typ: Option<Box<Type>>
|
||||
},
|
||||
ForLoop {
|
||||
init: Box<Ast>,
|
||||
@@ -66,6 +71,9 @@ pub enum Expr {
|
||||
left: Box<LocBox<Expr>>,
|
||||
right: Box<LocBox<Type>>
|
||||
},
|
||||
Self_ {
|
||||
strct: Option<Ident>
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Hash, PartialEq, PartialOrd)]
|
||||
@@ -102,6 +110,12 @@ pub struct CallParams(pub Vec<LocBox<Expr>>);
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Hash)]
|
||||
pub struct Block(pub Vec<Ast>);
|
||||
|
||||
impl Default for Block {
|
||||
fn default() -> Self {
|
||||
Self(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Hash)]
|
||||
pub struct Path(pub Vec<Ident>);
|
||||
|
||||
|
||||
@@ -9,10 +9,14 @@ pub enum Literal {
|
||||
Ident(Ident),
|
||||
String(TString),
|
||||
Char(Char),
|
||||
Array(Vec<LocBox<Expr>>),
|
||||
Array{
|
||||
items: Vec<LocBox<Expr>>,
|
||||
item_size: Option<usize>,
|
||||
},
|
||||
Bool(bool),
|
||||
ArrayRepeat {
|
||||
val: Box<LocBox<Expr>>,
|
||||
item_size: Option<usize>,
|
||||
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 })))}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ pub struct Scope {
|
||||
pub inner_scope: Option<Box<Scope>>
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Program {
|
||||
pub ast: expr::Block,
|
||||
pub structs: HashMap<Ident, LocBox<Struct>>,
|
||||
@@ -32,7 +32,9 @@ pub struct Program {
|
||||
pub literals: HashMap<String, Literal>, // string is id of literal
|
||||
pub struct_literals: HashMap<String, StructLit>, // string is id of literal
|
||||
pub scope: Option<Scope>,
|
||||
pub curr_fn_args: HashMap<Ident, LocBox<Type>>
|
||||
pub curr_fn_args: HashMap<Ident, LocBox<Type>>,
|
||||
pub curr_struct: Option<Ident>,
|
||||
pub included_files: Vec<String>,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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<Block>, // 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<ConstDataTyp>)
|
||||
}
|
||||
|
||||
pub fn get_constant_data_as_bytes(program: &Program, struct_items: &HashMap<Ident, usize>, value: LocBox<Expr>, is_big_endian: bool, must_be_number: bool) -> anyhow::Result<ConstDataTyp> {
|
||||
lazy_static!(
|
||||
static ref CTX: Mutex<ConstantCalcCtx> = Mutex::new(ConstantCalcCtx::default());
|
||||
);
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
struct ConstantCalcCtx {
|
||||
current_array_item_size: Option<usize>,
|
||||
current_struct_items: Option<HashMap<Ident, usize>>,
|
||||
current_struct_item_name: Option<Ident>
|
||||
}
|
||||
|
||||
|
||||
pub fn get_constant_data_as_bytes(program: &Program, value: LocBox<Expr>, is_big_endian: bool, must_be_number: bool) -> anyhow::Result<ConstDataTyp> {
|
||||
match value.inner() {
|
||||
Expr::Literal(_, lit) => {
|
||||
match lit {
|
||||
@@ -154,11 +193,28 @@ pub fn get_constant_data_as_bytes(program: &Program, struct_items: &HashMap<Iden
|
||||
lerror!(value.loc(), "Expected number got string");
|
||||
bail!("")
|
||||
}
|
||||
let mut val = val.chars().into_iter().map(|v| v as u8).collect::<Vec<u8>>();
|
||||
|
||||
if *cstr {
|
||||
let mut val = val.chars().into_iter().map(|v| v as u8).collect::<Vec<u8>>();
|
||||
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::<Vec<u8>>();
|
||||
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<Iden
|
||||
|
||||
Ok(ConstDataTyp::Bytes(buf))
|
||||
}
|
||||
Literal::Array(arr) => {
|
||||
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<Iden
|
||||
if arr.len() < 1 {
|
||||
return Ok(ConstDataTyp::Bytes(vec![]));
|
||||
}
|
||||
CTX.lock().unwrap().current_array_item_size = *item_size;
|
||||
for item in arr {
|
||||
let data = get_constant_data_as_bytes(program, struct_items, item.clone(), is_big_endian, must_be_number)?;
|
||||
let data = get_constant_data_as_bytes(program, item.clone(), is_big_endian, must_be_number)?;
|
||||
bytes.push(data);
|
||||
}
|
||||
CTX.lock().unwrap().current_array_item_size = None;
|
||||
|
||||
Ok(ConstDataTyp::Array(bytes))
|
||||
}
|
||||
Literal::ArrayRepeat { val, count } => {
|
||||
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<Iden
|
||||
items.insert(name.clone(), item.inner().size_of(program)?);
|
||||
}
|
||||
|
||||
CTX.lock().unwrap().current_struct_items = Some(items);
|
||||
|
||||
for field in &strct.fields {
|
||||
bytes.push(get_constant_data_as_bytes(program, &items, field.1.clone(), is_big_endian, must_be_number)?);
|
||||
CTX.lock().unwrap().current_struct_item_name = Some(field.0.clone());
|
||||
bytes.push(get_constant_data_as_bytes(program, field.1.clone(), is_big_endian, must_be_number)?);
|
||||
}
|
||||
CTX.lock().unwrap().current_struct_item_name = None;
|
||||
|
||||
Ok(ConstDataTyp::Array(bytes))
|
||||
}
|
||||
Expr::Path(path) => {
|
||||
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!("")
|
||||
|
||||
@@ -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<Self> {
|
||||
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<Self> {
|
||||
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 {
|
||||
|
||||
@@ -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<Token>, precedence: usize, consume_semi: bool, cli: &CliArgs) -> Result<Option<LocBox<Expr>>> {
|
||||
pub fn parse_expr(tokens: &mut Vec<Token>, precedence: usize, consume_semi: bool, cli: &CliArgs, prog: &mut Program) -> Result<Option<LocBox<Expr>>> {
|
||||
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<Token>, 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<Token>, 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<Token>, 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<Token>, 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<Token>, precedence: usize, consume_semi: bool
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn parse_return(tokens: &mut Vec<Token>, cli: &CliArgs) -> Result<LocBox<Expr>> {
|
||||
fn parse_return(tokens: &mut Vec<Token>, cli: &CliArgs, prog: &mut Program) -> Result<LocBox<Expr>> {
|
||||
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<Token>, left: LocBox<Expr>) -> Result<LocBox<Expr
|
||||
right: Box::new(typ)
|
||||
}))
|
||||
}
|
||||
fn parse_if(tokens: &mut Vec<Token>, cli: &CliArgs) -> Result<IfExpr> {
|
||||
fn parse_if(tokens: &mut Vec<Token>, cli: &CliArgs, prog: &mut Program) -> Result<IfExpr> {
|
||||
let loc = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::If), "")?;
|
||||
let _ = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenL), "")?;
|
||||
let Some(test) = parse_expr(tokens, 0, false, 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<Token>, cli: &CliArgs) -> Result<IfExpr> {
|
||||
_ = 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<Token>, cli: &CliArgs) -> Result<IfExpr> {
|
||||
};
|
||||
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<Token>, cli: &CliArgs) -> Result<IfExpr> {
|
||||
})
|
||||
}
|
||||
}
|
||||
fn parse_while_loop(tokens: &mut Vec<Token>, cli: &CliArgs) -> Result<LocBox<Expr>> {
|
||||
fn parse_while_loop(tokens: &mut Vec<Token>, cli: &CliArgs, prog: &mut Program) -> Result<LocBox<Expr>> {
|
||||
let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::While), "")?;
|
||||
let _ = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenL), "")?;
|
||||
let Some(test) = parse_expr(tokens, 0, false, 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<Token>, cli: &CliArgs) -> Result<LocBox<Expr>> {
|
||||
fn parse_for_loop(tokens: &mut Vec<Token>, cli: &CliArgs, prog: &mut Program) -> Result<LocBox<Expr>> {
|
||||
let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::For), "")?;
|
||||
let _ = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenL), "")?;
|
||||
let Some(pre) = parse_item(tokens, 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<Token>, cli: &CliArgs) -> Result<LocBox<Expr>
|
||||
body: block
|
||||
}))
|
||||
}
|
||||
fn parse_inf_loop(tokens: &mut Vec<Token>, cli: &CliArgs) -> Result<LocBox<Expr>> {
|
||||
fn parse_inf_loop(tokens: &mut Vec<Token>, cli: &CliArgs, prog: &mut Program) -> Result<LocBox<Expr>> {
|
||||
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<Token>, left: LocBox<Expr>, cli: &CliArgs) -> Result<LocBox<Expr>> {
|
||||
fn parse_fn_call(tokens: &mut Vec<Token>, left: LocBox<Expr>, cli: &CliArgs, prog: &mut Program) -> Result<LocBox<Expr>> {
|
||||
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<Token>, left: LocBox<Expr>, 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<Token>, left: LocBox<Expr>, 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<Token>, left: LocBox<Expr>, cli: &CliArgs) -> Result<LocBox<Expr>> {
|
||||
fn parse_array_index(tokens: &mut Vec<Token>, left: LocBox<Expr>, cli: &CliArgs, prog: &mut Program) -> Result<LocBox<Expr>> {
|
||||
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<Token>, left: LocBox<Expr>) -> Result<Loc
|
||||
Ok(LocBox::new(start.loc(), Expr::FieldAccess {
|
||||
left: Box::new(Some(left)),
|
||||
right: Box::new(right),
|
||||
offset: 0
|
||||
offset: 0,
|
||||
l_typ: None,
|
||||
r_typ: None
|
||||
}))
|
||||
}
|
||||
|
||||
fn parse_member_function_call(tokens: &mut Vec<Token>, left: LocBox<Expr>, cli: &CliArgs) -> Result<LocBox<Expr>> {
|
||||
fn parse_member_function_call(tokens: &mut Vec<Token>, left: LocBox<Expr>, cli: &CliArgs, prog: &mut Program) -> Result<LocBox<Expr>> {
|
||||
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<Token>, left: LocBox<Expr>, 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<Token>, left: LocBox<Expr>, 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<Token>, left: LocBox<Expr>) -> 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<Token>, cli: &CliArgs) -> Result<LocBox<Expr>> {
|
||||
fn parse_literal(tokens: &mut Vec<Token>, cli: &CliArgs, prog: &mut Program) -> Result<LocBox<Expr>> {
|
||||
if let Some(tkn) = utils::check_consume(tokens, TokenType::Keyword(Keyword::True)) {
|
||||
return Ok(LocBox::new(tkn.loc(), Expr::Literal(String::new(), Literal::Bool(true))));
|
||||
} else
|
||||
@@ -352,17 +360,17 @@ fn parse_literal(tokens: &mut Vec<Token>, cli: &CliArgs) -> Result<LocBox<Expr>>
|
||||
} 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<Token>, cli: &CliArgs) -> Result<LocBox<Expr>>
|
||||
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<Token>, cli: &CliArgs) -> Result<LocBox<Expr>>
|
||||
}
|
||||
}
|
||||
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<Token>, cli: &CliArgs) -> Result<LocBox<Expr>>
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn parse_struct_literal(tokens: &mut Vec<Token>, name: Path, cli: &CliArgs) -> Result<LocBox<Expr>> {
|
||||
fn parse_struct_literal(tokens: &mut Vec<Token>, name: Path, cli: &CliArgs, prog: &mut Program) -> Result<LocBox<Expr>> {
|
||||
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<Token>, 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<Token>, name: Path, cli: &CliArgs) -> R
|
||||
Ok(LocBox::new(start.loc(), Expr::Struct(String::new(), StructLit { path: name, fields })))
|
||||
}
|
||||
|
||||
fn parse_group(tokens: &mut Vec<Token>, cli: &CliArgs) -> Result<LocBox<Expr>> {
|
||||
fn parse_group(tokens: &mut Vec<Token>, cli: &CliArgs, prog: &mut Program) -> Result<LocBox<Expr>> {
|
||||
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<Token>) -> Result<LocBox<Expr>> {
|
||||
Ok(LocBox::new(part.loc(), Expr::Path(Path(buf))))
|
||||
}
|
||||
|
||||
fn parse_unop(tokens: &mut Vec<Token>, cli: &CliArgs) -> Result<LocBox<Expr>> {
|
||||
fn parse_unop(tokens: &mut Vec<Token>, cli: &CliArgs, prog: &mut Program) -> Result<LocBox<Expr>> {
|
||||
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<Token>, cli: &CliArgs) -> Result<LocBox<Expr>> {
|
||||
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<Token>, cli: &CliArgs) -> Result<LocBox<Expr>> {
|
||||
}))
|
||||
}
|
||||
|
||||
fn parse_binop(tokens: &mut Vec<Token>, mut lhs: LocBox<Expr>, precedence: usize, cli: &CliArgs) -> Result<LocBox<Expr>> {
|
||||
fn parse_binop(tokens: &mut Vec<Token>, mut lhs: LocBox<Expr>, precedence: usize, cli: &CliArgs, prog: &mut Program) -> Result<LocBox<Expr>> {
|
||||
// TODO: https://en.wikipedia.org/wiki/Operator-precedence_parser#Pseudocode
|
||||
|
||||
loop {
|
||||
@@ -501,7 +507,7 @@ fn parse_binop(tokens: &mut Vec<Token>, mut lhs: LocBox<Expr>, 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<Token>, mut lhs: LocBox<Expr>, precedence: usize
|
||||
|
||||
}
|
||||
|
||||
pub fn parse_block(tokens: &mut Vec<Token>, cli: &CliArgs) -> Result<Block> {
|
||||
pub fn parse_block(tokens: &mut Vec<Token>, cli: &CliArgs, prog: &mut Program) -> Result<Block> {
|
||||
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;
|
||||
|
||||
@@ -14,18 +14,8 @@ type Result<T> = anyhow::Result<T>;
|
||||
|
||||
pub fn parse_program(mut tokens: Vec<Token>, cli: &CliArgs) -> Result<Program> {
|
||||
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<Token>, cli: &CliArgs) -> Result<Program> {
|
||||
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<Token>, cli: &CliArgs) -> Result<Option<Ast>> {
|
||||
if let Some(stat) = stat::parse_statement(tokens, cli)? {
|
||||
fn parse_item(tokens: &mut Vec<Token>, cli: &CliArgs, prog: &mut Program) -> Result<Option<Ast>> {
|
||||
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)
|
||||
|
||||
@@ -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<T> = anyhow::Result<T>;
|
||||
|
||||
pub fn parse_statement(tokens: &mut Vec<Token>, cli: &CliArgs) -> Result<Option<LocBox<Statement>>> {
|
||||
pub fn parse_statement(tokens: &mut Vec<Token>, cli: &CliArgs, prog: &mut Program) -> Result<Option<LocBox<Statement>>> {
|
||||
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<Token>, cli: &CliArgs) -> Result<Option<
|
||||
Ok(Some(parse_enum(tokens)?))
|
||||
} else
|
||||
if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::Let)) {
|
||||
Ok(Some(parse_let(tokens, cli)?))
|
||||
Ok(Some(parse_let(tokens, cli, prog)?))
|
||||
} else
|
||||
if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::Include)) {
|
||||
Ok(Some(parse_include(tokens, cli)?))
|
||||
Ok(Some(parse_include(tokens, cli, prog)?))
|
||||
} else {
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_include(tokens: &mut Vec<Token>, cli: &CliArgs) -> Result<LocBox<Statement>> {
|
||||
fn parse_include(tokens: &mut Vec<Token>, cli: &CliArgs, prog: &mut Program) -> Result<LocBox<Statement>> {
|
||||
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<Token>, cli: &CliArgs) -> Result<LocBox<Statem
|
||||
let path = cwd.join(p);
|
||||
let path = path.join(&include_path.val);
|
||||
if path.exists() {
|
||||
// This is the first path that the include found the file, so if its already included,
|
||||
// skip it. Because the context is per file specified in the cli (not includes), that
|
||||
// means weird includes (probably) wont clash
|
||||
if prog.included_files.contains(&path.to_string_lossy().to_string()) {
|
||||
break;
|
||||
}
|
||||
prog.included_files.push(path.to_string_lossy().to_string().clone());
|
||||
let data = std::fs::read_to_string(&path)?;
|
||||
let mut tokens_imp = crate::tokeniser::tokenise(&data, &path.to_string_lossy().to_string())?;
|
||||
tokens.append(&mut tokens_imp);
|
||||
@@ -122,14 +131,14 @@ fn parse_struct(tokens: &mut Vec<Token>) -> Result<LocBox<Statement>> {
|
||||
Ok(LocBox::new(kw.loc(), Statement::Struct(Struct { name, fields })))
|
||||
}
|
||||
|
||||
fn parse_static(tokens: &mut Vec<Token>, cli: &CliArgs) -> Result<LocBox<Statement>> {
|
||||
fn parse_static(tokens: &mut Vec<Token>, cli: &CliArgs, prog: &mut Program) -> Result<LocBox<Statement>> {
|
||||
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<Token>, cli: &CliArgs) -> Result<LocBox<Stateme
|
||||
Ok(LocBox::new(kw.loc(), Statement::StaticVar(StaticVar { name, typ, val })))
|
||||
}
|
||||
|
||||
fn parse_let(tokens: &mut Vec<Token>, cli: &CliArgs) -> Result<LocBox<Statement>> {
|
||||
fn parse_let(tokens: &mut Vec<Token>, cli: &CliArgs, prog: &mut Program) -> Result<LocBox<Statement>> {
|
||||
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<Token>, cli: &CliArgs) -> Result<LocBox<Statement>
|
||||
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<Token>, cli: &CliArgs) -> Result<LocBox<Statement>
|
||||
_ = 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<Token>, cli: &CliArgs) -> Result<LocBox<Statement>> {
|
||||
fn parse_constant(tokens: &mut Vec<Token>, cli: &CliArgs, prog: &mut Program) -> Result<LocBox<Statement>> {
|
||||
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<Token>, cli: &CliArgs) -> Result<LocBox<State
|
||||
_ = 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!("")
|
||||
};
|
||||
@@ -183,10 +192,10 @@ fn parse_type_alias(tokens: &mut Vec<Token>) -> Result<LocBox<Statement>> {
|
||||
Ok(LocBox::new(kw.loc(), Statement::TypeAlias(TypeAlias { name, typ })))
|
||||
}
|
||||
|
||||
fn parse_fn(tokens: &mut Vec<Token>, cli: &CliArgs) -> Result<LocBox<Statement>> {
|
||||
fn parse_fn(tokens: &mut Vec<Token>, cli: &CliArgs, prog: &mut Program) -> Result<LocBox<Statement>> {
|
||||
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<Token>, cli: &CliArgs) -> Result<LocBox<Statement>>
|
||||
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<Token>, cli: &CliArgs) -> Result<LocBox<Statement>>
|
||||
}
|
||||
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<Token>, cli: &CliArgs) -> Result<LocBox<Statement>>
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn parse_fn_params(tokens: &mut Vec<Token>) -> Result<Vec<(Ident, LocBox<Type>)>> {
|
||||
// usize is: 0 = no self, static; 1 = self, ref; 2 = self, mut ref
|
||||
fn parse_fn_params(tokens: &mut Vec<Token>) -> Result<(usize, Vec<(Ident, LocBox<Type>)>)> {
|
||||
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<Token>) -> Result<Vec<(Ident, LocBox<Type>)>
|
||||
}
|
||||
|
||||
utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenR), "")?;
|
||||
Ok(args)
|
||||
Ok((dis, args))
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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<Token>) -> Result<LocBox<Type>> {
|
||||
}
|
||||
let itm_typ = parse_type(tokens)?;
|
||||
if let Some(_) = utils::check_consume(tokens, TokenType::Punct(Punctuation::Semi)) {
|
||||
let count = parse_expr(tokens, 0, false, &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<Token>) -> Result<LocBox<Type>> {
|
||||
_ = 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());
|
||||
}
|
||||
|
||||
@@ -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<PathBuf>, to: &Path) -> anyhow::Result<()>;
|
||||
fn link(&mut self, from: Vec<PathBuf>, to: &Path, extra_args: &Vec<String>) -> anyhow::Result<()>;
|
||||
}
|
||||
|
||||
@@ -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<std::path::PathBuf>, to: &std::path::Path) -> anyhow::Result<()> {
|
||||
fn link(&mut self, from: Vec<std::path::PathBuf>, to: &std::path::Path, extra_args: &Vec<String>) -> 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<Ident, VarMapT>,
|
||||
stack_offset: usize,
|
||||
used_registers: usize,
|
||||
loop_level: usize, // used for loops
|
||||
if_level: usize, // used for if stats
|
||||
cmp_level: usize, // used for logical comparisons
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<Vec<Token>> {
|
||||
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)),
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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<Statement>, 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<Option<Type>> {
|
||||
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<Option<Type
|
||||
|
||||
}
|
||||
|
||||
pub fn validate_expr(prog: &mut Program, expr: &mut Expr) -> anyhow::Result<Option<Type>> {
|
||||
match expr {
|
||||
pub fn validate_expr(prog: &mut Program, expr: &mut LocBox<Expr>) -> anyhow::Result<Option<Type>> {
|
||||
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<Opti
|
||||
validate_type(prog, &LocBox::new(&Loc::default(), typ.clone()))?;
|
||||
|
||||
for field in strct.fields.iter_mut() {
|
||||
validate_expr(prog, field.1.inner_mut())?;
|
||||
validate_expr(prog, field.1)?;
|
||||
}
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
@@ -122,7 +133,7 @@ pub fn validate_expr(prog: &mut Program, expr: &mut Expr) -> anyhow::Result<Opti
|
||||
Ok(Some(typ))
|
||||
},
|
||||
Expr::If(ifs) => {
|
||||
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<Opti
|
||||
// TODO: Path hell TBD
|
||||
Ok(Some(Type::Owned(path.0.last().unwrap().clone())))
|
||||
}
|
||||
Expr::Group(group) => 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<Opti
|
||||
match f {
|
||||
Some(func) => {
|
||||
for (i, param) in params.0.iter_mut().enumerate() {
|
||||
let ft = func.inner().params[i].1.inner().clone();
|
||||
let t = validate_expr(prog, param.inner_mut())?.clone();
|
||||
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<Opti
|
||||
Some(func) => {
|
||||
for (i, param) in params.0.iter_mut().enumerate() {
|
||||
let ft = func.inner().params[i].1.inner().clone();
|
||||
let t = validate_expr(prog, param.inner_mut())?.clone();
|
||||
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<Opti
|
||||
|
||||
|
||||
}
|
||||
Expr::MethodCall { left, params } => {
|
||||
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<Opti
|
||||
let Type::Owned(struct_name) = var_t.unwrap().get_absolute_value(prog)? else {
|
||||
panic!("fml");
|
||||
};
|
||||
|
||||
*strct = Some(struct_name.clone());
|
||||
let mut strct = prog.member_functions.get_mut(&struct_name).unwrap().clone();
|
||||
let func = strct.get_mut(&method_name).unwrap();
|
||||
|
||||
for (i, param) in params.0.iter_mut().enumerate() {
|
||||
let t = validate_expr(prog, param.inner_mut())?;
|
||||
let t = validate_expr(prog, param)?;
|
||||
let ft = func.inner_mut().params[i].1.inner_mut();
|
||||
if t.as_ref() != Some(ft) {
|
||||
lerror!(param.loc(), "expected {ft}, got {}", t.unwrap());
|
||||
@@ -254,15 +267,15 @@ pub fn validate_expr(prog: &mut Program, expr: &mut Expr) -> anyhow::Result<Opti
|
||||
}
|
||||
Expr::ForLoop { init, test, on_loop, body } => {
|
||||
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<Opti
|
||||
(*lit).hash(&mut hasher);
|
||||
let hash = hasher.finish();
|
||||
*id = hash.to_string();
|
||||
|
||||
match lit {
|
||||
Literal::Array { items, item_size } => {
|
||||
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<Opti
|
||||
}
|
||||
Punctuation::Minus |
|
||||
Punctuation::Plus => {
|
||||
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<Opti
|
||||
}
|
||||
|
||||
Punctuation::Ampersand => {
|
||||
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<Opti
|
||||
Punctuation::Shr => {
|
||||
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<Opti
|
||||
Punctuation::Ge |
|
||||
Punctuation::AndAnd |
|
||||
Punctuation::OrOr => {
|
||||
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<Opti
|
||||
Punctuation::AndEq |
|
||||
Punctuation::OrEq |
|
||||
Punctuation::XorEq => {
|
||||
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<Opti
|
||||
Ok(None)
|
||||
}
|
||||
Punctuation::Eq => {
|
||||
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<Opti
|
||||
}
|
||||
},
|
||||
Expr::ArrayIndex { name, index } => {
|
||||
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<Opti
|
||||
}
|
||||
f(prog, &left, name.loc(), &index)
|
||||
},
|
||||
Expr::PtrFieldAccess { left, right, offset } |
|
||||
Expr::FieldAccess { left, right, offset } => {
|
||||
let left = validate_expr(prog, left.clone().unwrap().inner_mut())?;
|
||||
let right = validate_expr(prog, right.clone().inner_mut())?.unwrap();
|
||||
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<Opti
|
||||
Ok(None)
|
||||
},
|
||||
Expr::WhileLoop { test, body } => {
|
||||
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<Opti
|
||||
|
||||
fn validate_fn(prog: &mut Program, func: &mut Function) -> 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<Ast>) -> any
|
||||
fn validate_type(prog: &mut Program, typ: &LocBox<Type>) -> anyhow::Result<Type> {
|
||||
fn f(prog: &mut Program, typ: &Type, loc: &Loc) -> anyhow::Result<Type> {
|
||||
match typ {
|
||||
Type::SizedArray { inner, .. } |
|
||||
Type::UnsizedArray { inner, .. } |
|
||||
Type::Ref { inner, .. } => f(prog, inner, loc),
|
||||
Type::SizedArray { .. } |
|
||||
Type::UnsizedArray { .. } |
|
||||
Type::Ref { .. } => Ok(typ.clone()),
|
||||
Type::Owned(ident) => {
|
||||
if let Some(builtin) = get_builtin_from_name(&ident.0) {
|
||||
Ok(builtin)
|
||||
|
||||
@@ -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<Type> = [
|
||||
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<Type> {
|
||||
if let Some(t) = TYPES_RAW.get(name) {
|
||||
Some(Type::Builtin { name: name.to_string(), size: t.0 as u8, signed: t.1 })
|
||||
} else {
|
||||
None
|
||||
pub fn get_builtin_from_name(type_name: &str) -> Option<Type> {
|
||||
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 {
|
||||
|
||||
2
std/core.mcl
Normal file
2
std/core.mcl
Normal file
@@ -0,0 +1,2 @@
|
||||
include "std/str.mcl";
|
||||
include "std/io/mod.mcl";
|
||||
12
std/io/mod.mcl
Normal file
12
std/io/mod.mcl
Normal file
@@ -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);
|
||||
}
|
||||
107
std/lib/beaker.mcl
Normal file
107
std/lib/beaker.mcl
Normal file
@@ -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;
|
||||
|
||||
14
std/str.mcl
Normal file
14
std/str.mcl
Normal file
@@ -0,0 +1,14 @@
|
||||
type cstr = [u8];
|
||||
|
||||
|
||||
struct str {
|
||||
len: usize,
|
||||
inner: &cstr
|
||||
}
|
||||
|
||||
fn str.len(&self) -> usize {
|
||||
return self.len;
|
||||
}
|
||||
|
||||
|
||||
|
||||
6
test.mcl
6
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 {
|
||||
|
||||
6
test2.mcl
Normal file
6
test2.mcl
Normal file
@@ -0,0 +1,6 @@
|
||||
// include "std/core.mcl";
|
||||
include "beaker.mcl";
|
||||
|
||||
fn main() -> i32 {
|
||||
//puts("owo\n");
|
||||
}
|
||||
1
tests/mod.rs
Normal file
1
tests/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
mod parser;
|
||||
3
tests/parser/expr.rs
Normal file
3
tests/parser/expr.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
|
||||
3
tests/parser/mod.rs
Normal file
3
tests/parser/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
mod expr;
|
||||
mod stat;
|
||||
mod typ;
|
||||
0
tests/parser/stat.rs
Normal file
0
tests/parser/stat.rs
Normal file
190
tests/parser/typ.rs
Normal file
190
tests/parser/typ.rs
Normal file
@@ -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");
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
[]
|
||||
Reference in New Issue
Block a user