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>) {
asm (a1 = &msg) {
asm (a1 = msg@) {
ld a2, 8, a1
ld a1, 0, a1
li a0, 1
@@ -140,7 +140,7 @@ fn print_hex(x: 64) {
c = add(c, 7);
};
c = add(c, 48);
asm (a1 = &c) {
asm (a1 = c@) {
li a2, 1
li a0, 1
li a7, 64
@@ -176,7 +176,7 @@ fn print_dec(x: 64) {
c = add(c, 7);
};
c = add(c, 48);
asm (a1 = &c) {
asm (a1 = c@) {
li a2, 1
li a0, 1
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
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?
TYPE IDS!!!!! MY SAVIOR!!! MY GOAT!!!

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)
}
} 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 => "@",
}
}
}