random spot with parser rewrite (still broken)

This commit is contained in:
2025-04-27 02:32:28 -04:00
parent a087af505e
commit d7222cc7a4
16 changed files with 240 additions and 260 deletions

View File

@@ -122,7 +122,7 @@ fn println(msg: slice<8>) {
} }
fn print(msg: slice<8>) { fn print(msg: slice<8>) {
asm (a1 = &msg) { asm (a1 = msg@) {
ld a2, 8, a1 ld a2, 8, a1
ld a1, 0, a1 ld a1, 0, a1
li a0, 1 li a0, 1
@@ -140,7 +140,7 @@ fn print_hex(x: 64) {
c = add(c, 7); c = add(c, 7);
}; };
c = add(c, 48); c = add(c, 48);
asm (a1 = &c) { asm (a1 = c@) {
li a2, 1 li a2, 1
li a0, 1 li a0, 1
li a7, 64 li a7, 64
@@ -176,7 +176,7 @@ fn print_dec(x: 64) {
c = add(c, 7); c = add(c, 7);
}; };
c = add(c, 48); c = add(c, 48);
asm (a1 = &c) { asm (a1 = c@) {
li a2, 1 li a2, 1
li a0, 1 li a0, 1
li a7, 64 li a7, 64

4
ideas
View File

@@ -15,3 +15,7 @@ for each var, create list of constraints on type
for global vars yes, in functions no for global vars yes, in functions no
but if function returns are inferrable (even if just "impl Trait"), then needed in functions? but if function returns are inferrable (even if just "impl Trait"), then needed in functions?
every kind has an origin, should make separate like names? every kind has an origin, should make separate like names?
TYPE IDS!!!!! MY SAVIOR!!! MY GOAT!!!

View File

@@ -50,6 +50,7 @@ const BEFORE: usize = 1;
const AFTER: usize = 0; const AFTER: usize = 0;
impl FileSpan { impl FileSpan {
const BUILTIN_FILE: usize = usize::MAX;
pub fn at(pos: FilePos) -> Self { pub fn at(pos: FilePos) -> Self {
Self { Self {
start: pos, start: pos,
@@ -57,7 +58,21 @@ impl FileSpan {
file: pos.file, file: pos.file,
} }
} }
pub fn builtin() -> Self {
let pos = FilePos {
file: Self::BUILTIN_FILE,
line: 0,
col: 0,
};
Self::at(pos)
}
pub fn is_builtin(&self) -> bool {
self.file == Self::BUILTIN_FILE
}
pub fn write_for(&self, writer: &mut impl std::io::Write, file: &str) -> std::io::Result<()> { pub fn write_for(&self, writer: &mut impl std::io::Write, file: &str) -> std::io::Result<()> {
if self.is_builtin() {
return Ok(());
}
let start = self.start.line.saturating_sub(BEFORE); let start = self.start.line.saturating_sub(BEFORE);
let num_before = self.start.line - start; let num_before = self.start.line - start;
let mut lines = file.lines().skip(start); let mut lines = file.lines().skip(start);

View File

@@ -82,7 +82,7 @@ pub struct LFunctionBuilderData<'a> {
instrs: Vec<LInstruction>, instrs: Vec<LInstruction>,
stack: HashMap<VarID, Size>, stack: HashMap<VarID, Size>,
subvar_map: HashMap<VarID, VarOffset>, subvar_map: HashMap<VarID, VarOffset>,
struct_insts: HashMap<StructTy, StructInst>, struct_insts: HashMap<StructInst, StructInst>,
makes_call: bool, makes_call: bool,
loopp: Option<LoopCtx>, loopp: Option<LoopCtx>,
} }
@@ -268,7 +268,7 @@ impl<'a> LFunctionBuilder<'a> {
self.data.instrs.push(LInstruction::Ret { src }) self.data.instrs.push(LInstruction::Ret { src })
} }
UInstruction::Construct { dest, fields } => { UInstruction::Construct { dest, fields } => {
let sty = &self.program.expect(dest.id).ty; let sty = &self.program.expect_type(dest.id);
let Type::Struct(sty) = sty else { let Type::Struct(sty) = sty else {
panic!("bruh htis aint' a struct"); panic!("bruh htis aint' a struct");
}; };
@@ -379,7 +379,7 @@ impl LFunctionBuilderData<'_> {
pub fn struct_inst(&mut self, p: &UProgram, ty: &StructTy) -> &StructInst { pub fn struct_inst(&mut self, p: &UProgram, ty: &StructTy) -> &StructInst {
// normally I'd let Some(..) here and return, but polonius does not exist :grief: // normally I'd let Some(..) here and return, but polonius does not exist :grief:
if self.struct_insts.get(ty).is_none() { if self.struct_insts.get(ty).is_none() {
let StructTy { id, args } = ty; let StructInst { id, args } = ty;
let struc = p.expect(*id); let struc = p.expect(*id);
let mut types = Vec::new(); let mut types = Vec::new();
let mut sizes = struc let mut sizes = struc
@@ -423,7 +423,7 @@ impl LFunctionBuilderData<'_> {
self.struct_insts.get(ty).unwrap() self.struct_insts.get(ty).unwrap()
} }
pub fn field_offset(&mut self, p: &UProgram, sty: &StructTy, field: &str) -> Option<Len> { pub fn field_offset(&mut self, p: &UProgram, sty: &StructInst, field: &str) -> Option<Len> {
let inst = self.struct_inst(p, sty); let inst = self.struct_inst(p, sty);
Some(inst.offset(field)?) Some(inst.offset(field)?)
} }

View File

@@ -28,7 +28,7 @@ pub struct UGeneric {}
#[derive(Clone)] #[derive(Clone)]
pub struct UVar { pub struct UVar {
pub ty: Type, pub ty: TypeID,
} }
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
@@ -48,12 +48,8 @@ pub type Origin = FileSpan;
impl UFunc { impl UFunc {
pub fn ty(&self, program: &UProgram) -> Type { pub fn ty(&self, program: &UProgram) -> Type {
Type::Fn { Type::Fn {
args: self args: self.args.iter().map(|a| program.expect(*a).ty).collect(),
.args ret: self.ret,
.iter()
.map(|a| program.expect(*a).ty.clone())
.collect(),
ret: Box::new(self.ret.clone()),
} }
} }
pub fn flat_iter(&self) -> impl Iterator<Item = &UInstrInst> { pub fn flat_iter(&self) -> impl Iterator<Item = &UInstrInst> {
@@ -116,15 +112,15 @@ macro_rules! impl_kind {
impl_kind!(UFunc, 0, fns, "func", nofin); impl_kind!(UFunc, 0, fns, "func", nofin);
impl_kind!(UVar, 1, vars, "var"); impl_kind!(UVar, 1, vars, "var");
impl_kind!(UStruct, 2, structs, "struct"); impl_kind!(UStruct, 2, structs, "struct");
impl_kind!(UGeneric, 3, types, "type"); impl_kind!(Type, 3, types, "type");
impl_kind!(UData, 4, data, "data"); impl_kind!(UData, 4, data, "data");
pub const NAMED_KINDS: usize = 6; pub const NAMED_KINDS: usize = 5;
pub type FnID = ID<UFunc>; pub type FnID = ID<UFunc>;
pub type VarID = ID<UVar>; pub type VarID = ID<UVar>;
pub type StructID = ID<UStruct>; pub type StructID = ID<UStruct>;
pub type DataID = ID<UData>; pub type DataID = ID<UData>;
pub type GenericID = ID<UGeneric>; pub type TypeID = ID<Type>;
impl Finish for UFunc { impl Finish for UFunc {
fn finish(p: &mut UProgram, id: ID<Self>, name: &str) { fn finish(p: &mut UProgram, id: ID<Self>, name: &str) {

View File

@@ -6,13 +6,14 @@ pub struct UProgram {
pub fns: Vec<Option<UFunc>>, pub fns: Vec<Option<UFunc>>,
pub vars: Vec<Option<UVar>>, pub vars: Vec<Option<UVar>>,
pub structs: Vec<Option<UStruct>>, pub structs: Vec<Option<UStruct>>,
pub types: Vec<Option<UGeneric>>, pub types: Vec<Option<Type>>,
pub data: Vec<Option<UData>>, pub data: Vec<Option<UData>>,
// associated data // associated data
pub names: NameMap, pub names: NameMap,
pub origins: OriginMap, pub origins: OriginMap,
pub fn_var: FnVarMap, pub fn_var: FnVarMap,
// utils for creation // utils for creation
error: Option<TypeID>,
pub path: Vec<String>, pub path: Vec<String>,
pub name_stack: Vec<HashMap<String, Idents>>, pub name_stack: Vec<HashMap<String, Idents>>,
pub temp: usize, pub temp: usize,
@@ -29,11 +30,16 @@ impl UProgram {
names: NameMap::new(), names: NameMap::new(),
origins: OriginMap::new(), origins: OriginMap::new(),
fn_var: FnVarMap::new(), fn_var: FnVarMap::new(),
error: None,
path: Vec::new(), path: Vec::new(),
name_stack: Vec::new(), name_stack: Vec::new(),
temp: 0, temp: 0,
} }
} }
pub fn error_type(&mut self) -> TypeID {
self.error
.unwrap_or_else(|| self.def("error", Some(Type::Error), Origin::builtin()))
}
pub fn set_module(&mut self, path: Vec<String>) { pub fn set_module(&mut self, path: Vec<String>) {
self.path = path; self.path = path;
self.name_stack = vec![HashMap::new()]; self.name_stack = vec![HashMap::new()];
@@ -69,6 +75,9 @@ impl UProgram {
self.get(id) self.get(id)
.unwrap_or_else(|| panic!("{id:?} not defined yet!")) .unwrap_or_else(|| panic!("{id:?} not defined yet!"))
} }
pub fn expect_type(&self, var: VarID) -> &Type {
self.expect(self.expect(var).ty)
}
pub fn expect_mut<K: Kind + Named>(&mut self, id: ID<K>) -> &mut K { pub fn expect_mut<K: Kind + Named>(&mut self, id: ID<K>) -> &mut K {
self.get_mut(id) self.get_mut(id)
.unwrap_or_else(|| panic!("{id:?} not defined yet!")) .unwrap_or_else(|| panic!("{id:?} not defined yet!"))
@@ -77,16 +86,12 @@ impl UProgram {
self.fns[self.fn_var.fun(id)?.0].as_ref() self.fns[self.fn_var.fun(id)?.0].as_ref()
} }
pub fn temp_var(&mut self, origin: Origin, ty: impl Into<Type>) -> VarInst { pub fn temp_var(&mut self, origin: Origin, ty: TypeID) -> VarInst {
self.temp_var_inner(origin, ty) self.temp_var_inner(origin, ty)
} }
fn temp_var_inner(&mut self, origin: Origin, ty: impl Into<Type>) -> VarInst { fn temp_var_inner(&mut self, origin: Origin, ty: TypeID) -> VarInst {
let v = self.def( let v = self.def(&format!("temp{}", self.temp), Some(UVar { ty }), origin);
&format!("temp{}", self.temp),
Some(UVar { ty: ty.into() }),
origin,
);
self.temp += 1; self.temp += 1;
VarInst { VarInst {
id: v, id: v,
@@ -128,76 +133,64 @@ impl UProgram {
id id
} }
pub fn struct_field_type<'a>(&'a self, sty: &'a StructTy, field: &str) -> Option<&'a Type> { // hopefully these are not needed after redoing types
let struc = self.get(sty.id)?; // pub fn field_type<'a>(&'a self, ty: &'a Type, field: &str) -> Option<&'a Type> {
let field = struc.fields.get(field)?; // if let Type::Struct(sty) = ty {
if let Type::Generic { id } = field.ty { // Some(&self.get(*sty.fields.get(field)?)?.ty)
for (i, g) in struc.generics.iter().enumerate() { // } else if let Type::Module(path) = ty {
if *g == id { // let id = self.names.id::<UVar>(path, field)?;
return Some(&sty.args[i]); // Some(&self.get(id)?.ty)
} // } else {
} // None
} // }
Some(&field.ty) // }
} //
// pub fn follow_ref(&self, m: &FieldRef) -> Option<&Type> {
pub fn field_type<'a>(&'a self, ty: &'a Type, field: &str) -> Option<&'a Type> { // let parent = self.get(m.parent)?;
if let Type::Struct(sty) = ty { // self.field_type(self.follow_type(&parent.ty)?, &m.name)
self.struct_field_type(sty, field) // }
} else if let Type::Module(path) = ty { //
let id = self.names.id::<UVar>(path, field)?; // pub fn get_type<'a>(&'a self, v: VarID) -> Option<&'a Type> {
Some(&self.get(id)?.ty) // self.follow_type(&self.get(v)?.ty)
} else { // }
None //
} // pub fn set_type(&mut self, mut var: VarID, set: Type) -> Option<()> {
} // let mut path = Vec::new();
// while let Type::Field(parent) = &self.get(var)?.ty {
pub fn follow_ref(&self, m: &FieldRef) -> Option<&Type> { // var = parent.parent;
let parent = self.get(m.parent)?; // path.push(parent.name.clone());
self.field_type(self.follow_type(&parent.ty)?, &m.name) // }
} // let mut ty = &mut self.vars[var.0].as_mut()?.ty;
// 'outer: while let Type::Struct(sty) = ty {
pub fn get_type<'a>(&'a self, v: VarID) -> Option<&'a Type> { // let Some(name) = path.pop() else {
self.follow_type(&self.get(v)?.ty) // break;
} // };
// let struc = &self.structs[sty.id.0].as_ref()?;
pub fn set_type(&mut self, mut var: VarID, set: Type) -> Option<()> { // let field = struc.fields.get(&name)?;
let mut path = Vec::new(); // let Type::Generic { id } = field.ty else {
while let Type::Field(parent) = &self.get(var)?.ty { // return None;
var = parent.parent; // };
path.push(parent.name.clone()); // for (i, g) in struc.generics.iter().enumerate() {
} // if *g == id {
let mut ty = &mut self.vars[var.0].as_mut()?.ty; // ty = &mut sty.args[i];
'outer: while let Type::Struct(sty) = ty { // continue 'outer;
let Some(name) = path.pop() else { // }
break; // }
}; // return None;
let struc = &self.structs[sty.id.0].as_ref()?; // }
let field = struc.fields.get(&name)?; // *ty = set;
let Type::Generic { id } = field.ty else { // Some(())
return None; // }
}; //
for (i, g) in struc.generics.iter().enumerate() { // pub fn follow_type<'a>(&'a self, ty: &'a Type) -> Option<&'a Type> {
if *g == id { // match ty {
ty = &mut sty.args[i]; // Type::Field(m) => {
continue 'outer; // let parent = self.get(m.parent)?;
} // self.field_type(self.follow_type(&parent.ty)?, &m.name)
} // }
return None; // ty => Some(ty),
} // }
*ty = set; // }
Some(())
}
pub fn follow_type<'a>(&'a self, ty: &'a Type) -> Option<&'a Type> {
match ty {
Type::Field(m) => {
let parent = self.get(m.parent)?;
self.field_type(self.follow_type(&parent.ty)?, &m.name)
}
ty => Some(ty),
}
}
pub fn type_name(&self, ty: &Type) -> String { pub fn type_name(&self, ty: &Type) -> String {
let mut str = String::new(); let mut str = String::new();

View File

@@ -1,6 +1,6 @@
use std::collections::HashMap; use std::collections::HashMap;
use super::{assoc::NamePath, GenericID, Len, StructID, UInstruction, UProgram, UVar, VarID}; use super::{assoc::NamePath, Len, StructID, TypeID, UInstruction, UProgram, VarID};
#[derive(Debug, Clone, Hash, Eq, PartialEq)] #[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct FieldRef { pub struct FieldRef {
@@ -8,22 +8,20 @@ pub struct FieldRef {
pub name: String, pub name: String,
} }
#[derive(Clone, Hash, Eq, PartialEq)] #[derive(Clone, Eq, PartialEq)]
pub struct StructTy { pub struct StructTy {
pub id: StructID, pub id: StructID,
pub args: Vec<Type>, pub fields: HashMap<String, VarID>,
} }
#[derive(Clone, PartialEq, Eq, Hash)] #[derive(Clone, PartialEq, Eq)]
pub enum Type { pub enum Type {
Bits(u32), Bits(u32),
Struct(StructTy), Struct(StructTy),
// is this real? I don't know, it's kind of like infer Fn { args: Vec<TypeID>, ret: TypeID },
Generic { id: GenericID }, Ref(TypeID),
Fn { args: Vec<Type>, ret: Box<Type> }, Slice(TypeID),
Ref(Box<Type>), Array(TypeID, Len),
Slice(Box<Type>),
Array(Box<Type>, Len),
Unit, Unit,
// fake types // fake types
Field(FieldRef), Field(FieldRef),
@@ -37,15 +35,6 @@ impl Type {
pub fn is_resolved(&self) -> bool { pub fn is_resolved(&self) -> bool {
!matches!(self, Self::Error | Self::Placeholder | Self::Infer) !matches!(self, Self::Error | Self::Placeholder | Self::Infer)
} }
pub fn rf(self) -> Self {
Type::Ref(Box::new(self))
}
pub fn arr(self, len: Len) -> Self {
Type::Array(Box::new(self), len)
}
pub fn slice(self) -> Self {
Type::Slice(Box::new(self))
}
} }
impl UProgram { impl UProgram {

View File

@@ -4,7 +4,7 @@ use crate::common::FileID;
use super::{ use super::{
CompilerMsg, CompilerOutput, MaybeParsable, Node, NodeParseResult, Parsable, ParsableWith, CompilerMsg, CompilerOutput, MaybeParsable, Node, NodeParseResult, Parsable, ParsableWith,
TokenCursor, ParseResult, TokenCursor,
}; };
pub struct ParserCtx<'a> { pub struct ParserCtx<'a> {

View File

@@ -1,7 +1,7 @@
use super::{func::FnLowerCtx, FnLowerable, PExpr, UnaryOp}; use super::{func::FnLowerCtx, FnLowerable, PExpr, PostfixOp};
use crate::{ use crate::{
ir::{FieldRef, Type, UData, UInstruction, VarInst}, ir::{FieldRef, Type, UData, UInstruction, VarInst},
parser::PInfixOp, parser::InfixOp,
}; };
impl FnLowerable for PExpr { impl FnLowerable for PExpr {
@@ -56,13 +56,13 @@ impl FnLowerable for PExpr {
}, },
PExpr::Ident(i) => ctx.get_var(i)?, PExpr::Ident(i) => ctx.get_var(i)?,
PExpr::BinaryOp(op, e1, e2) => match op { PExpr::BinaryOp(op, e1, e2) => match op {
PInfixOp::Add => todo!(), InfixOp::Add => todo!(),
PInfixOp::Sub => todo!(), InfixOp::Sub => todo!(),
PInfixOp::Mul => todo!(), InfixOp::Mul => todo!(),
PInfixOp::Div => todo!(), InfixOp::Div => todo!(),
PInfixOp::LessThan => todo!(), InfixOp::LessThan => todo!(),
PInfixOp::GreaterThan => todo!(), InfixOp::GreaterThan => todo!(),
PInfixOp::Member => { InfixOp::Member => {
let res1 = e1.lower(ctx)?; let res1 = e1.lower(ctx)?;
let Some(box PExpr::Ident(ident)) = &e2.inner else { let Some(box PExpr::Ident(ident)) = &e2.inner else {
ctx.err("Field accessors must be identifiers".to_string()); ctx.err("Field accessors must be identifiers".to_string());
@@ -74,7 +74,7 @@ impl FnLowerable for PExpr {
name: fname, name: fname,
})) }))
} }
PInfixOp::Assign => { InfixOp::Assign => {
let res1 = e1.lower(ctx)?; let res1 = e1.lower(ctx)?;
let res2 = e2.lower(ctx)?; let res2 = e2.lower(ctx)?;
ctx.push(UInstruction::Mv { ctx.push(UInstruction::Mv {
@@ -84,10 +84,10 @@ impl FnLowerable for PExpr {
res1 res1
} }
}, },
PExpr::UnaryOp(op, e) => { PExpr::PostfixOp(op, e) => {
let res = e.lower(ctx)?; let res = e.lower(ctx)?;
match op { match op {
UnaryOp::Ref => { PostfixOp::Ref => {
let temp = ctx.temp(ctx.program.expect(res.id).ty.clone().rf()); let temp = ctx.temp(ctx.program.expect(res.id).ty.clone().rf());
ctx.push(UInstruction::Ref { ctx.push(UInstruction::Ref {
dest: temp, dest: temp,
@@ -95,7 +95,7 @@ impl FnLowerable for PExpr {
}); });
temp temp
} }
UnaryOp::Deref => { PostfixOp::Deref => {
let t = &ctx.program.expect(res.id).ty; let t = &ctx.program.expect(res.id).ty;
let Type::Ref(_) = t else { let Type::Ref(_) = t else {
ctx.err(format!( ctx.err(format!(
@@ -106,7 +106,7 @@ impl FnLowerable for PExpr {
}; };
todo!(); todo!();
} }
UnaryOp::Not => todo!(), PostfixOp::Not => todo!(),
} }
} }
PExpr::Block(b) => b.lower(ctx)?, PExpr::Block(b) => b.lower(ctx)?,

View File

@@ -1,12 +1,12 @@
use crate::{ use crate::{
common::{CompilerOutput, FileSpan}, common::{CompilerOutput, FileSpan},
ir::{StructField, StructID, UInstruction, UProgram, UStruct, VarInst}, ir::{StructField, StructID, UInstruction, UProgram, UStruct, VarInst},
parser::{Node, PConstruct, PConstructFields, PStruct, PStructFields}, parser::{Node, PMap, PConstructFields, PStruct, PStructFields},
}; };
use super::{FnLowerCtx, FnLowerable}; use super::{FnLowerCtx, FnLowerable};
impl FnLowerable for PConstruct { impl FnLowerable for PMap {
type Output = VarInst; type Output = VarInst;
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> { fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
let ty = self.name.lower(ctx.program, ctx.output); let ty = self.name.lower(ctx.program, ctx.output);

View File

@@ -1,12 +1,12 @@
use crate::{ use crate::{
ir::{GenericID, StructTy, Type, UGeneric, UProgram, UStruct}, ir::{StructInst, Type, TypeID, UGeneric, UProgram, UStruct},
parser::PGenericDef, parser::PGenericDef,
}; };
use super::{CompilerMsg, CompilerOutput, FileSpan, Node, PType}; use super::{CompilerMsg, CompilerOutput, FileSpan, Node, PType};
impl Node<PType> { impl Node<PType> {
pub fn lower(&self, namespace: &mut UProgram, output: &mut CompilerOutput) -> Type { pub fn lower(&self, namespace: &mut UProgram, output: &mut CompilerOutput) -> TypeID {
self.as_ref() self.as_ref()
.map(|t| t.lower(namespace, output, self.origin)) .map(|t| t.lower(namespace, output, self.origin))
.unwrap_or(Type::Error) .unwrap_or(Type::Error)
@@ -14,17 +14,17 @@ impl Node<PType> {
} }
impl PType { impl PType {
pub fn lower(&self, p: &mut UProgram, output: &mut CompilerOutput, span: FileSpan) -> Type { pub fn lower(&self, p: &mut UProgram, output: &mut CompilerOutput, span: FileSpan) -> TypeID {
let Some(name) = self.name.as_ref() else { let Some(name) = self.name.as_ref() else {
return Type::Error; return p.error_type();
}; };
let ids = p.get_idents(name); let ids = p.get_idents(name);
// TODO: should generics always take precedence? // TODO: should generics always take precedence?
if let Some(id) = ids.and_then(|ids| ids.get::<UGeneric>()) { if let Some(id) = ids.and_then(|ids| ids.get::<Type>()) {
Type::Generic { id } Type::Generic { id }
} else if let Some(id) = ids.and_then(|ids| ids.get::<UStruct>()) { } else if let Some(id) = ids.and_then(|ids| ids.get::<UStruct>()) {
let args = self.args.iter().map(|n| n.lower(p, output)).collect(); let args = self.args.iter().map(|n| n.lower(p, output)).collect();
Type::Struct(StructTy { id, args }) Type::Struct(StructInst { id, args })
} else if let Ok(num) = name.parse::<u32>() { } else if let Ok(num) = name.parse::<u32>() {
Type::Bits(num) Type::Bits(num)
} else { } else {

View File

@@ -3,10 +3,10 @@ use std::fmt::{Debug, Write};
use crate::{common::FilePos, parser::NodeParsableWith}; use crate::{common::FilePos, parser::NodeParsableWith};
use super::{ use super::{
op::{PInfixOp, UnaryOp}, op::{InfixOp, PostfixOp},
util::parse_list, util::parse_list,
CompilerMsg, Keyword, Node, PAsmBlock, PBlock, PConstruct, PIdent, PLiteral, CompilerMsg, Keyword, Node, PAsmBlock, PBlock, PIdent, PLiteral, PMap, Parsable, ParseResult,
Parsable, ParseResult, ParserCtx, Symbol, ParserCtx, Symbol,
}; };
type BoxNode = Node<Box<PExpr>>; type BoxNode = Node<Box<PExpr>>;
@@ -14,13 +14,14 @@ type BoxNode = Node<Box<PExpr>>;
pub enum PExpr { pub enum PExpr {
Lit(Node<PLiteral>), Lit(Node<PLiteral>),
Ident(Node<PIdent>), Ident(Node<PIdent>),
BinaryOp(PInfixOp, BoxNode, BoxNode), BinaryOp(InfixOp, BoxNode, BoxNode),
UnaryOp(UnaryOp, BoxNode), PostfixOp(BoxNode, PostfixOp),
Block(Node<PBlock>), Block(Node<PBlock>),
Call(BoxNode, Vec<Node<PExpr>>), Call(BoxNode, Vec<Node<PExpr>>),
Group(BoxNode), Group(BoxNode),
Access(BoxNode, Node<PIdent>),
AsmBlock(Node<PAsmBlock>), AsmBlock(Node<PAsmBlock>),
Construct(Node<PConstruct>), Construct(BoxNode, Node<PMap>),
If(BoxNode, BoxNode), If(BoxNode, BoxNode),
Loop(BoxNode), Loop(BoxNode),
Break, Break,
@@ -30,8 +31,58 @@ pub enum PExpr {
impl Parsable for PExpr { impl Parsable for PExpr {
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> { fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
let start = ctx.next_start(); let start = ctx.next_start();
let mut e1 = Self::parse_unit_postfix(ctx)?;
while let Some(op) = ctx
.peek()
.map(|next| InfixOp::from_token(&next.token))
.flatten()
{
let span = start.to(ctx.prev_end());
ctx.next();
let n2 = ctx.parse()?.bx();
let (n1, op, n2) = fix_precedence(Node::new(e1, span).bx(), op, n2, start);
e1 = Self::BinaryOp(op, n1, n2);
}
return ParseResult::Ok(e1);
}
}
impl PExpr {
fn parse_unit_postfix(ctx: &mut ParserCtx) -> ParseResult<Self> {
let start = ctx.next_start();
// first get unit
let mut e1 = Self::parse_unit(ctx)?;
// then apply post ops
loop {
let span = start.to(ctx.prev_end());
let Some(next) = ctx.peek() else {
break;
};
if next.is_symbol(Symbol::OpenParen) {
ctx.next();
let args = parse_list(ctx, Symbol::CloseParen)?;
e1 = Self::Call(Node::new(e1, span).bx(), args);
continue;
} else if next.is_symbol(Symbol::OpenCurly) {
let map = ctx.parse()?;
e1 = Self::Construct(Node::new(e1, span).bx(), map);
continue;
} else if next.is_symbol(Symbol::Dot) {
let field = ctx.parse()?;
e1 = Self::Access(Node::new(e1, span).bx(), field);
continue;
} else if let Some(op) = PostfixOp::from_token(next) {
ctx.next();
e1 = Self::PostfixOp(Node::new(e1, span).bx(), op);
continue;
}
break;
}
return ParseResult::Ok(e1);
}
fn parse_unit(ctx: &mut ParserCtx) -> ParseResult<Self> {
let next = ctx.expect_peek()?; let next = ctx.expect_peek()?;
let mut e1 = if next.is_symbol(Symbol::OpenParen) { return ParseResult::Ok(if next.is_symbol(Symbol::OpenParen) {
ctx.next(); ctx.next();
if ctx.expect_peek()?.is_symbol(Symbol::CloseParen) { if ctx.expect_peek()?.is_symbol(Symbol::CloseParen) {
ctx.next(); ctx.next();
@@ -67,75 +118,28 @@ impl Parsable for PExpr {
} else if next.is_keyword(Keyword::Asm) { } else if next.is_keyword(Keyword::Asm) {
ctx.next(); ctx.next();
Self::AsmBlock(ctx.parse()?) Self::AsmBlock(ctx.parse()?)
} else if let Some(op) = UnaryOp::from_token(next) {
ctx.next();
return ctx.parse().map(|n| {
let n = n.bx();
if let Some(box Self::BinaryOp(op2, n1, n2)) = n.inner {
let span = start.to(n1.origin.end);
Self::BinaryOp(op2, Node::new(Self::UnaryOp(op, n1), span).bx(), n2)
} else {
Self::UnaryOp(op, n)
}
});
} else if let Some(val) = ctx.maybe_parse() { } else if let Some(val) = ctx.maybe_parse() {
Self::Lit(val) Self::Lit(val)
} else { } else {
let res = ctx.parse(); let res = ctx.parse();
if res.node.is_some() { if res.node.is_some() {
// TODO: this is extremely limiting
// maybe parse generically and then during lowering figure out what's a function vs
// struct vs etc like mentioned in main.rs
if let Some(next) = ctx.peek()
&& next.is_symbol(Symbol::OpenCurly)
{
Self::Construct(ctx.parse_with(res.node)?)
} else {
Self::Ident(res.node) Self::Ident(res.node)
}
} else { } else {
let next = ctx.expect_peek()?; let next = ctx.expect_peek()?;
return ParseResult::Err(CompilerMsg::unexpected_token(next, "an expression")); return ParseResult::Err(CompilerMsg::unexpected_token(next, "an expression"));
} }
}; });
let Some(mut next) = ctx.peek() else {
return ParseResult::Ok(e1);
};
while next.is_symbol(Symbol::OpenParen) {
ctx.next();
let args = parse_list(ctx, Symbol::CloseParen)?;
let end = ctx.prev_end();
e1 = Self::Call(Node::new(Box::new(e1), start.to(end)), args);
let Some(next2) = ctx.peek() else {
return ParseResult::Ok(e1);
};
next = next2
}
let end = ctx.prev_end();
let mut recover = false;
let res = if let Some(op) = PInfixOp::from_token(&next.token) {
ctx.next();
let n1 = Node::new(e1, start.to(end)).bx();
let res = ctx.parse();
let n2 = res.node.bx();
recover = res.recover;
let (n1, op, n2) = fix_precedence(n1, op, n2, start);
Self::BinaryOp(op, n1, n2)
} else {
e1
};
ParseResult::from_recover(res, recover)
} }
} }
pub fn fix_precedence( pub fn fix_precedence(
mut n1: BoxNode, mut n1: BoxNode,
mut op: PInfixOp, mut op: InfixOp,
mut n2: BoxNode, mut n2: BoxNode,
start: FilePos, start: FilePos,
) -> (BoxNode, PInfixOp, BoxNode) { ) -> (BoxNode, InfixOp, BoxNode) {
if let Some(box PExpr::BinaryOp(op2, _, _)) = n2.as_ref() { if let Some(box PExpr::BinaryOp(op2, _, _)) = n2.as_ref() {
if op.precedence() >= op2.precedence() { if op.precedence() > op2.precedence() {
let Some(box PExpr::BinaryOp(op2, n21, n22)) = n2.inner else { let Some(box PExpr::BinaryOp(op2, n21, n22)) = n2.inner else {
unreachable!(); unreachable!();
}; };
@@ -176,14 +180,15 @@ impl Debug for PExpr {
} }
f.write_char(')')?; f.write_char(')')?;
} }
PExpr::UnaryOp(op, e) => write!(f, "({}{:?})", op.str(), e)?, PExpr::PostfixOp(e, op) => write!(f, "({:?}{})", e, op.str())?,
PExpr::Group(inner) => inner.fmt(f)?, PExpr::Group(inner) => inner.fmt(f)?,
PExpr::AsmBlock(inner) => inner.fmt(f)?, PExpr::AsmBlock(inner) => inner.fmt(f)?,
PExpr::Construct(inner) => inner.fmt(f)?, PExpr::Construct(node, inner) => inner.fmt(f)?,
PExpr::If(cond, res) => write!(f, "if {cond:?} then {res:?}")?, PExpr::If(cond, res) => write!(f, "if {cond:?} then {res:?}")?,
PExpr::Loop(res) => write!(f, "loop -> {res:?}")?, PExpr::Loop(res) => write!(f, "loop -> {res:?}")?,
PExpr::Break => write!(f, "break")?, PExpr::Break => write!(f, "break")?,
PExpr::Continue => write!(f, "continue")?, PExpr::Continue => write!(f, "continue")?,
PExpr::Access(e1, name) => write!(f, "{:?}.{:?}", e1, name)?,
} }
Ok(()) Ok(())
} }

View File

@@ -1,18 +1,17 @@
use super::{Symbol, Token}; use super::{Symbol, Token};
#[derive(Debug, PartialEq, Eq, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum PInfixOp { pub enum InfixOp {
Add, Add,
Sub, Sub,
Mul, Mul,
Div, Div,
LessThan, LessThan,
GreaterThan, GreaterThan,
Member,
Assign, Assign,
} }
impl PInfixOp { impl InfixOp {
pub fn precedence(&self) -> u32 { pub fn precedence(&self) -> u32 {
match self { match self {
Self::Assign => 0, Self::Assign => 0,
@@ -22,7 +21,6 @@ impl PInfixOp {
Self::Sub => 3, Self::Sub => 3,
Self::Mul => 4, Self::Mul => 4,
Self::Div => 5, Self::Div => 5,
Self::Member => 6,
} }
} }
pub fn str(&self) -> &str { pub fn str(&self) -> &str {
@@ -33,7 +31,6 @@ impl PInfixOp {
Self::Div => "/", Self::Div => "/",
Self::LessThan => "<", Self::LessThan => "<",
Self::GreaterThan => ">", Self::GreaterThan => ">",
Self::Member => ".",
Self::Assign => "=", Self::Assign => "=",
} }
} }
@@ -45,19 +42,18 @@ impl PInfixOp {
Self::Div => true, Self::Div => true,
Self::LessThan => true, Self::LessThan => true,
Self::GreaterThan => true, Self::GreaterThan => true,
Self::Member => false,
Self::Assign => true, Self::Assign => true,
} }
} }
} }
pub enum UnaryOp { pub enum PostfixOp {
Not, Not,
Ref, Ref,
Deref, Deref,
} }
impl PInfixOp { impl InfixOp {
pub fn from_token(token: &Token) -> Option<Self> { pub fn from_token(token: &Token) -> Option<Self> {
let Token::Symbol(symbol) = token else { let Token::Symbol(symbol) = token else {
return None; return None;
@@ -69,7 +65,6 @@ impl PInfixOp {
Symbol::Minus => Self::Sub, Symbol::Minus => Self::Sub,
Symbol::Asterisk => Self::Mul, Symbol::Asterisk => Self::Mul,
Symbol::Slash => Self::Div, Symbol::Slash => Self::Div,
Symbol::Dot => Self::Member,
Symbol::Equals => Self::Assign, Symbol::Equals => Self::Assign,
_ => { _ => {
return None; return None;
@@ -78,11 +73,11 @@ impl PInfixOp {
} }
} }
impl UnaryOp { impl PostfixOp {
pub fn str(&self) -> &str { pub fn str(&self) -> &str {
match self { match self {
Self::Not => "!", Self::Not => "!",
Self::Ref => "&", Self::Ref => "@",
Self::Deref => "*", Self::Deref => "*",
} }
} }
@@ -91,7 +86,7 @@ impl UnaryOp {
return None; return None;
}; };
Some(match symbol { Some(match symbol {
Symbol::Ampersand => Self::Ref, Symbol::At => Self::Ref,
Symbol::Bang => Self::Not, Symbol::Bang => Self::Not,
Symbol::Asterisk => Self::Deref, Symbol::Asterisk => Self::Deref,
_ => { _ => {

View File

@@ -1,10 +1,10 @@
use std::fmt::Debug; use std::fmt::{Debug, Write};
use crate::parser::ParsableWith; use crate::{parser::ParsableWith, util::Padder};
use super::{ use super::{
util::parse_list, CompilerMsg, Keyword, Node, PExpr, PFieldDef, PIdent, PType, PGenericDef, util::parse_list, CompilerMsg, Node, PFieldDef, PGenericDef, PIdent, PType, PVarDef, Parsable,
PVarDef, Parsable, ParseResult, ParserCtx, Symbol, ParseResult, ParserCtx, Symbol,
}; };
#[derive(Debug)] #[derive(Debug)]
@@ -14,11 +14,7 @@ pub struct PStruct {
pub fields: PStructFields, pub fields: PStructFields,
} }
#[derive(Debug)] pub struct PMap(Vec<Node<PFieldDef>>);
pub struct PConstruct {
pub name: Node<PType>,
pub fields: PConstructFields,
}
#[derive(Debug)] #[derive(Debug)]
pub enum PStructFields { pub enum PStructFields {
@@ -27,13 +23,6 @@ pub enum PStructFields {
None, None,
} }
#[derive(Debug)]
pub enum PConstructFields {
Named(Vec<Node<PFieldDef>>),
Tuple(Vec<Node<PExpr>>),
None,
}
impl Parsable for PStruct { impl Parsable for PStruct {
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> { fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
let name = ctx.parse()?; let name = ctx.parse()?;
@@ -64,41 +53,29 @@ impl Parsable for PStruct {
fields: PStructFields::None, fields: PStructFields::None,
}); });
}; };
ParseResult::Ok(PStruct { name, generics: args, fields }) ParseResult::Ok(PStruct {
name,
generics: args,
fields,
})
} }
} }
impl ParsableWith for PConstruct { impl Parsable for PMap {
type Data = Node<PIdent>; fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
fn parse(ctx: &mut ParserCtx, name_node: Self::Data) -> ParseResult<Self> { ctx.expect_sym(Symbol::OpenCurly);
let next = ctx.expect_peek()?; ParseResult::Ok(Self(parse_list(ctx, Symbol::CloseCurly)?))
// TODO: this is not correct span; type should also span generics, which aren't even in }
// here yet }
let span = name_node.origin;
let name = Node::new( impl Debug for PMap {
PType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
name: name_node, writeln!(f, "{{")?;
args: Vec::new(), let mut padder = Padder::new(f);
}, for arg in &self.0 {
span, padder.write_str(&format!("{arg:?},\n"))?;
); }
let fields = if next.is_symbol(Symbol::Semicolon) { writeln!(f, "}}")?;
ctx.next(); Ok(())
PConstructFields::None
} else if next.is_symbol(Symbol::OpenCurly) {
ctx.next();
PConstructFields::Named(parse_list(ctx, Symbol::CloseCurly)?)
} else if next.is_symbol(Symbol::OpenParen) {
ctx.next();
PConstructFields::Tuple(parse_list(ctx, Symbol::CloseParen)?)
} else {
let msg = CompilerMsg::unexpected_token(next, "`;`, `(`, or `{`");
ctx.err(msg);
return ParseResult::Recover(PConstruct {
name,
fields: PConstructFields::None,
});
};
ParseResult::Ok(PConstruct { name, fields })
} }
} }

View File

@@ -133,7 +133,10 @@ impl<T: Parsable> ParsableWith for T {
impl<T: ParsableWith> Node<T> { impl<T: ParsableWith> Node<T> {
pub fn parse_with(ctx: &mut ParserCtx, data: T::Data) -> NodeParseResult<T> { pub fn parse_with(ctx: &mut ParserCtx, data: T::Data) -> NodeParseResult<T> {
let start = ctx.peek().map(|t| t.span.start).unwrap_or(FilePos::start(ctx.cursor.file())); let start = ctx
.peek()
.map(|t| t.span.start)
.unwrap_or(FilePos::start(ctx.cursor.file()));
let (inner, recover) = match T::parse(ctx, data) { let (inner, recover) = match T::parse(ctx, data) {
ParseResult::Ok(v) => (Some(v), false), ParseResult::Ok(v) => (Some(v), false),
ParseResult::Recover(v) => (Some(v), true), ParseResult::Recover(v) => (Some(v), true),

View File

@@ -35,6 +35,7 @@ pub enum Symbol {
DoublePipe, DoublePipe,
Comma, Comma,
Hash, Hash,
At,
} }
impl Symbol { impl Symbol {
@@ -70,6 +71,7 @@ impl Symbol {
'|' => Self::Pipe, '|' => Self::Pipe,
',' => Self::Comma, ',' => Self::Comma,
'#' => Self::Hash, '#' => Self::Hash,
'@' => Self::At,
_ => return None, _ => return None,
}) })
} }
@@ -144,6 +146,7 @@ impl Symbol {
Self::Pipe => "|", Self::Pipe => "|",
Self::DoublePipe => "||", Self::DoublePipe => "||",
Self::Hash => "#", Self::Hash => "#",
Self::At => "@",
} }
} }
} }