random spot with parser rewrite (still broken)
This commit is contained in:
@@ -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
4
ideas
@@ -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!!!
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)?)
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::common::FileID;
|
||||
|
||||
use super::{
|
||||
CompilerMsg, CompilerOutput, MaybeParsable, Node, NodeParseResult, Parsable, ParsableWith,
|
||||
TokenCursor,
|
||||
ParseResult, TokenCursor,
|
||||
};
|
||||
|
||||
pub struct ParserCtx<'a> {
|
||||
|
||||
@@ -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)?,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
_ => {
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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 => "@",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user