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

@@ -50,6 +50,7 @@ const BEFORE: usize = 1;
const AFTER: usize = 0;
impl FileSpan {
const BUILTIN_FILE: usize = usize::MAX;
pub fn at(pos: FilePos) -> Self {
Self {
start: pos,
@@ -57,7 +58,21 @@ impl FileSpan {
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<()> {
if self.is_builtin() {
return Ok(());
}
let start = self.start.line.saturating_sub(BEFORE);
let num_before = self.start.line - start;
let mut lines = file.lines().skip(start);

View File

@@ -82,7 +82,7 @@ pub struct LFunctionBuilderData<'a> {
instrs: Vec<LInstruction>,
stack: HashMap<VarID, Size>,
subvar_map: HashMap<VarID, VarOffset>,
struct_insts: HashMap<StructTy, StructInst>,
struct_insts: HashMap<StructInst, StructInst>,
makes_call: bool,
loopp: Option<LoopCtx>,
}
@@ -268,7 +268,7 @@ impl<'a> LFunctionBuilder<'a> {
self.data.instrs.push(LInstruction::Ret { src })
}
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 {
panic!("bruh htis aint' a struct");
};
@@ -379,7 +379,7 @@ impl LFunctionBuilderData<'_> {
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:
if self.struct_insts.get(ty).is_none() {
let StructTy { id, args } = ty;
let StructInst { id, args } = ty;
let struc = p.expect(*id);
let mut types = Vec::new();
let mut sizes = struc
@@ -423,7 +423,7 @@ impl LFunctionBuilderData<'_> {
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);
Some(inst.offset(field)?)
}

View File

@@ -28,7 +28,7 @@ pub struct UGeneric {}
#[derive(Clone)]
pub struct UVar {
pub ty: Type,
pub ty: TypeID,
}
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
@@ -48,12 +48,8 @@ pub type Origin = FileSpan;
impl UFunc {
pub fn ty(&self, program: &UProgram) -> Type {
Type::Fn {
args: self
.args
.iter()
.map(|a| program.expect(*a).ty.clone())
.collect(),
ret: Box::new(self.ret.clone()),
args: self.args.iter().map(|a| program.expect(*a).ty).collect(),
ret: self.ret,
}
}
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!(UVar, 1, vars, "var");
impl_kind!(UStruct, 2, structs, "struct");
impl_kind!(UGeneric, 3, types, "type");
impl_kind!(Type, 3, types, "type");
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 VarID = ID<UVar>;
pub type StructID = ID<UStruct>;
pub type DataID = ID<UData>;
pub type GenericID = ID<UGeneric>;
pub type TypeID = ID<Type>;
impl Finish for UFunc {
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 vars: Vec<Option<UVar>>,
pub structs: Vec<Option<UStruct>>,
pub types: Vec<Option<UGeneric>>,
pub types: Vec<Option<Type>>,
pub data: Vec<Option<UData>>,
// associated data
pub names: NameMap,
pub origins: OriginMap,
pub fn_var: FnVarMap,
// utils for creation
error: Option<TypeID>,
pub path: Vec<String>,
pub name_stack: Vec<HashMap<String, Idents>>,
pub temp: usize,
@@ -29,11 +30,16 @@ impl UProgram {
names: NameMap::new(),
origins: OriginMap::new(),
fn_var: FnVarMap::new(),
error: None,
path: Vec::new(),
name_stack: Vec::new(),
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>) {
self.path = path;
self.name_stack = vec![HashMap::new()];
@@ -69,6 +75,9 @@ impl UProgram {
self.get(id)
.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 {
self.get_mut(id)
.unwrap_or_else(|| panic!("{id:?} not defined yet!"))
@@ -77,16 +86,12 @@ impl UProgram {
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)
}
fn temp_var_inner(&mut self, origin: Origin, ty: impl Into<Type>) -> VarInst {
let v = self.def(
&format!("temp{}", self.temp),
Some(UVar { ty: ty.into() }),
origin,
);
fn temp_var_inner(&mut self, origin: Origin, ty: TypeID) -> VarInst {
let v = self.def(&format!("temp{}", self.temp), Some(UVar { ty }), origin);
self.temp += 1;
VarInst {
id: v,
@@ -128,76 +133,64 @@ impl UProgram {
id
}
pub fn struct_field_type<'a>(&'a self, sty: &'a StructTy, field: &str) -> Option<&'a Type> {
let struc = self.get(sty.id)?;
let field = struc.fields.get(field)?;
if let Type::Generic { id } = field.ty {
for (i, g) in struc.generics.iter().enumerate() {
if *g == id {
return Some(&sty.args[i]);
}
}
}
Some(&field.ty)
}
pub fn field_type<'a>(&'a self, ty: &'a Type, field: &str) -> Option<&'a Type> {
if let Type::Struct(sty) = ty {
self.struct_field_type(sty, field)
} else if let Type::Module(path) = ty {
let id = self.names.id::<UVar>(path, field)?;
Some(&self.get(id)?.ty)
} else {
None
}
}
pub fn follow_ref(&self, m: &FieldRef) -> Option<&Type> {
let parent = self.get(m.parent)?;
self.field_type(self.follow_type(&parent.ty)?, &m.name)
}
pub fn get_type<'a>(&'a self, v: VarID) -> Option<&'a Type> {
self.follow_type(&self.get(v)?.ty)
}
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 {
var = parent.parent;
path.push(parent.name.clone());
}
let mut ty = &mut self.vars[var.0].as_mut()?.ty;
'outer: while let Type::Struct(sty) = ty {
let Some(name) = path.pop() else {
break;
};
let struc = &self.structs[sty.id.0].as_ref()?;
let field = struc.fields.get(&name)?;
let Type::Generic { id } = field.ty else {
return None;
};
for (i, g) in struc.generics.iter().enumerate() {
if *g == id {
ty = &mut sty.args[i];
continue 'outer;
}
}
return None;
}
*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),
}
}
// hopefully these are not needed after redoing types
// pub fn field_type<'a>(&'a self, ty: &'a Type, field: &str) -> Option<&'a Type> {
// if let Type::Struct(sty) = ty {
// Some(&self.get(*sty.fields.get(field)?)?.ty)
// } else if let Type::Module(path) = ty {
// let id = self.names.id::<UVar>(path, field)?;
// Some(&self.get(id)?.ty)
// } else {
// None
// }
// }
//
// pub fn follow_ref(&self, m: &FieldRef) -> Option<&Type> {
// let parent = self.get(m.parent)?;
// self.field_type(self.follow_type(&parent.ty)?, &m.name)
// }
//
// pub fn get_type<'a>(&'a self, v: VarID) -> Option<&'a Type> {
// self.follow_type(&self.get(v)?.ty)
// }
//
// 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 {
// var = parent.parent;
// path.push(parent.name.clone());
// }
// let mut ty = &mut self.vars[var.0].as_mut()?.ty;
// 'outer: while let Type::Struct(sty) = ty {
// let Some(name) = path.pop() else {
// break;
// };
// let struc = &self.structs[sty.id.0].as_ref()?;
// let field = struc.fields.get(&name)?;
// let Type::Generic { id } = field.ty else {
// return None;
// };
// for (i, g) in struc.generics.iter().enumerate() {
// if *g == id {
// ty = &mut sty.args[i];
// continue 'outer;
// }
// }
// return None;
// }
// *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 {
let mut str = String::new();

View File

@@ -1,6 +1,6 @@
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)]
pub struct FieldRef {
@@ -8,22 +8,20 @@ pub struct FieldRef {
pub name: String,
}
#[derive(Clone, Hash, Eq, PartialEq)]
#[derive(Clone, Eq, PartialEq)]
pub struct StructTy {
pub id: StructID,
pub args: Vec<Type>,
pub fields: HashMap<String, VarID>,
}
#[derive(Clone, PartialEq, Eq, Hash)]
#[derive(Clone, PartialEq, Eq)]
pub enum Type {
Bits(u32),
Struct(StructTy),
// is this real? I don't know, it's kind of like infer
Generic { id: GenericID },
Fn { args: Vec<Type>, ret: Box<Type> },
Ref(Box<Type>),
Slice(Box<Type>),
Array(Box<Type>, Len),
Fn { args: Vec<TypeID>, ret: TypeID },
Ref(TypeID),
Slice(TypeID),
Array(TypeID, Len),
Unit,
// fake types
Field(FieldRef),
@@ -37,15 +35,6 @@ impl Type {
pub fn is_resolved(&self) -> bool {
!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 {

View File

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

View File

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

View File

@@ -1,12 +1,12 @@
use crate::{
ir::{GenericID, StructTy, Type, UGeneric, UProgram, UStruct},
ir::{StructInst, Type, TypeID, UGeneric, UProgram, UStruct},
parser::PGenericDef,
};
use super::{CompilerMsg, CompilerOutput, FileSpan, 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()
.map(|t| t.lower(namespace, output, self.origin))
.unwrap_or(Type::Error)
@@ -14,17 +14,17 @@ impl Node<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 {
return Type::Error;
return p.error_type();
};
let ids = p.get_idents(name);
// 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 }
} else if let Some(id) = ids.and_then(|ids| ids.get::<UStruct>()) {
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>() {
Type::Bits(num)
} else {

View File

@@ -3,10 +3,10 @@ use std::fmt::{Debug, Write};
use crate::{common::FilePos, parser::NodeParsableWith};
use super::{
op::{PInfixOp, UnaryOp},
op::{InfixOp, PostfixOp},
util::parse_list,
CompilerMsg, Keyword, Node, PAsmBlock, PBlock, PConstruct, PIdent, PLiteral,
Parsable, ParseResult, ParserCtx, Symbol,
CompilerMsg, Keyword, Node, PAsmBlock, PBlock, PIdent, PLiteral, PMap, Parsable, ParseResult,
ParserCtx, Symbol,
};
type BoxNode = Node<Box<PExpr>>;
@@ -14,13 +14,14 @@ type BoxNode = Node<Box<PExpr>>;
pub enum PExpr {
Lit(Node<PLiteral>),
Ident(Node<PIdent>),
BinaryOp(PInfixOp, BoxNode, BoxNode),
UnaryOp(UnaryOp, BoxNode),
BinaryOp(InfixOp, BoxNode, BoxNode),
PostfixOp(BoxNode, PostfixOp),
Block(Node<PBlock>),
Call(BoxNode, Vec<Node<PExpr>>),
Group(BoxNode),
Access(BoxNode, Node<PIdent>),
AsmBlock(Node<PAsmBlock>),
Construct(Node<PConstruct>),
Construct(BoxNode, Node<PMap>),
If(BoxNode, BoxNode),
Loop(BoxNode),
Break,
@@ -30,8 +31,58 @@ pub enum PExpr {
impl Parsable for PExpr {
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
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 mut e1 = if next.is_symbol(Symbol::OpenParen) {
return ParseResult::Ok(if next.is_symbol(Symbol::OpenParen) {
ctx.next();
if ctx.expect_peek()?.is_symbol(Symbol::CloseParen) {
ctx.next();
@@ -67,75 +118,28 @@ impl Parsable for PExpr {
} else if next.is_keyword(Keyword::Asm) {
ctx.next();
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() {
Self::Lit(val)
} else {
let res = ctx.parse();
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 {
let next = ctx.expect_peek()?;
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(
mut n1: BoxNode,
mut op: PInfixOp,
mut op: InfixOp,
mut n2: BoxNode,
start: FilePos,
) -> (BoxNode, PInfixOp, BoxNode) {
) -> (BoxNode, InfixOp, BoxNode) {
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 {
unreachable!();
};
@@ -176,14 +180,15 @@ impl Debug for PExpr {
}
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::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::Loop(res) => write!(f, "loop -> {res:?}")?,
PExpr::Break => write!(f, "break")?,
PExpr::Continue => write!(f, "continue")?,
PExpr::Access(e1, name) => write!(f, "{:?}.{:?}", e1, name)?,
}
Ok(())
}

View File

@@ -1,18 +1,17 @@
use super::{Symbol, Token};
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum PInfixOp {
pub enum InfixOp {
Add,
Sub,
Mul,
Div,
LessThan,
GreaterThan,
Member,
Assign,
}
impl PInfixOp {
impl InfixOp {
pub fn precedence(&self) -> u32 {
match self {
Self::Assign => 0,
@@ -22,7 +21,6 @@ impl PInfixOp {
Self::Sub => 3,
Self::Mul => 4,
Self::Div => 5,
Self::Member => 6,
}
}
pub fn str(&self) -> &str {
@@ -33,7 +31,6 @@ impl PInfixOp {
Self::Div => "/",
Self::LessThan => "<",
Self::GreaterThan => ">",
Self::Member => ".",
Self::Assign => "=",
}
}
@@ -45,19 +42,18 @@ impl PInfixOp {
Self::Div => true,
Self::LessThan => true,
Self::GreaterThan => true,
Self::Member => false,
Self::Assign => true,
}
}
}
pub enum UnaryOp {
pub enum PostfixOp {
Not,
Ref,
Deref,
}
impl PInfixOp {
impl InfixOp {
pub fn from_token(token: &Token) -> Option<Self> {
let Token::Symbol(symbol) = token else {
return None;
@@ -69,7 +65,6 @@ impl PInfixOp {
Symbol::Minus => Self::Sub,
Symbol::Asterisk => Self::Mul,
Symbol::Slash => Self::Div,
Symbol::Dot => Self::Member,
Symbol::Equals => Self::Assign,
_ => {
return None;
@@ -78,11 +73,11 @@ impl PInfixOp {
}
}
impl UnaryOp {
impl PostfixOp {
pub fn str(&self) -> &str {
match self {
Self::Not => "!",
Self::Ref => "&",
Self::Ref => "@",
Self::Deref => "*",
}
}
@@ -91,7 +86,7 @@ impl UnaryOp {
return None;
};
Some(match symbol {
Symbol::Ampersand => Self::Ref,
Symbol::At => Self::Ref,
Symbol::Bang => Self::Not,
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::{
util::parse_list, CompilerMsg, Keyword, Node, PExpr, PFieldDef, PIdent, PType, PGenericDef,
PVarDef, Parsable, ParseResult, ParserCtx, Symbol,
util::parse_list, CompilerMsg, Node, PFieldDef, PGenericDef, PIdent, PType, PVarDef, Parsable,
ParseResult, ParserCtx, Symbol,
};
#[derive(Debug)]
@@ -14,11 +14,7 @@ pub struct PStruct {
pub fields: PStructFields,
}
#[derive(Debug)]
pub struct PConstruct {
pub name: Node<PType>,
pub fields: PConstructFields,
}
pub struct PMap(Vec<Node<PFieldDef>>);
#[derive(Debug)]
pub enum PStructFields {
@@ -27,13 +23,6 @@ pub enum PStructFields {
None,
}
#[derive(Debug)]
pub enum PConstructFields {
Named(Vec<Node<PFieldDef>>),
Tuple(Vec<Node<PExpr>>),
None,
}
impl Parsable for PStruct {
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
let name = ctx.parse()?;
@@ -64,41 +53,29 @@ impl Parsable for PStruct {
fields: PStructFields::None,
});
};
ParseResult::Ok(PStruct { name, generics: args, fields })
ParseResult::Ok(PStruct {
name,
generics: args,
fields,
})
}
}
impl ParsableWith for PConstruct {
type Data = Node<PIdent>;
fn parse(ctx: &mut ParserCtx, name_node: Self::Data) -> ParseResult<Self> {
let next = ctx.expect_peek()?;
// 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(
PType {
name: name_node,
args: Vec::new(),
},
span,
);
let fields = if next.is_symbol(Symbol::Semicolon) {
ctx.next();
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 })
impl Parsable for PMap {
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
ctx.expect_sym(Symbol::OpenCurly);
ParseResult::Ok(Self(parse_list(ctx, Symbol::CloseCurly)?))
}
}
impl Debug for PMap {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "{{")?;
let mut padder = Padder::new(f);
for arg in &self.0 {
padder.write_str(&format!("{arg:?},\n"))?;
}
writeln!(f, "}}")?;
Ok(())
}
}

View File

@@ -133,7 +133,10 @@ impl<T: Parsable> ParsableWith for T {
impl<T: ParsableWith> Node<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) {
ParseResult::Ok(v) => (Some(v), false),
ParseResult::Recover(v) => (Some(v), true),

View File

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