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
+1 -1
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> {
+14 -14
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)?,
+2 -2
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);
+6 -6
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 {
+66 -61
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(())
}
+7 -12
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,
_ => {
+26 -49
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(())
}
}
+4 -1
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),
+3
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 => "@",
}
}
}