Compare commits

...

6 commits

Author SHA1 Message Date
janis 51ef019fd1
var decls 2025-10-14 15:10:03 +02:00
janis 0ee6bbad61
port symbol table from old crate 2025-10-14 13:52:39 +02:00
janis 0468f1fab3
remove eprintlns from lexer 2025-10-14 13:22:54 +02:00
janis a2632ca06e
function parsing and stuff.. 2025-10-13 23:37:06 +02:00
janis c7d5e4e6c0
parsing with indirect recursion 2025-10-13 23:08:15 +02:00
janis 2771593605
pretty printing ast, parsing functions 2025-10-13 22:02:22 +02:00
5 changed files with 1160 additions and 242 deletions

View file

@ -380,21 +380,14 @@ pub(crate) fn parse_comment<'a>(source: &'a mut Source) -> Result<bool> {
} }
let doc = source.next_if_eq(&'/').is_some(); let doc = source.next_if_eq(&'/').is_some();
eprintln!("doc comment: {doc}");
loop { loop {
// take until new line // take until new line
source source.take_while_inclusive(|&c| c != '\n').for_each(drop);
.take_while_inclusive(|&c| c != '\n')
.inspect(|c| eprintln!("skipping comment char: {c}"))
.for_each(drop);
let mut copy = source.clone(); let mut copy = source.clone();
// skip whitespaces after new line to find continuation of comment // skip whitespaces after new line to find continuation of comment
(&mut copy) (&mut copy)
.take_while_ref(|&c| { .take_while_ref(|&c| is_things::is_whitespace(c) && c != '\n')
eprintln!("Skipping whitespace: {c}");
is_things::is_whitespace(c) && c != '\n'
})
.for_each(drop); .for_each(drop);
if (copy.next() == Some('/')) && (copy.next() == Some('/')) { if (copy.next() == Some('/')) && (copy.next() == Some('/')) {

View file

@ -496,8 +496,6 @@ impl<'a> TokenIterator<'a> {
Some('/') if self.follows("//") => { Some('/') if self.follows("//") => {
let doc = complex_tokens::parse_comment(&mut source).ok()?; let doc = complex_tokens::parse_comment(&mut source).ok()?;
self.offset += source.offset(); self.offset += source.offset();
eprintln!("next: {:?}", source.next());
eprintln!("rest: {:?}", &self.source[self.offset..]);
let lexeme = &self.source[start..self.offset]; let lexeme = &self.source[start..self.offset];
if doc { if doc {

View file

@ -1,4 +1,4 @@
use std::{hash::Hash, ops::Range, sync::Arc}; use std::{fmt::Display, hash::Hash, ops::Range, sync::Arc};
use chumsky::{ use chumsky::{
IterParser, Parser, IterParser, Parser,
@ -6,8 +6,8 @@ use chumsky::{
extra::{self, SimpleState}, extra::{self, SimpleState},
input::{IterInput, MapExtra}, input::{IterInput, MapExtra},
pratt::{infix, left, postfix, prefix, right}, pratt::{infix, left, postfix, prefix, right},
prelude::{Recursive, choice, just, recursive}, prelude::{Recursive, choice, just, none_of, recursive, via_parser},
recursive::Direct, recursive::{Direct, Indirect},
select, text, select, text,
}; };
use internment::Intern; use internment::Intern;
@ -63,6 +63,86 @@ pub enum InnerType {
type Type = internment::Intern<InnerType>; type Type = internment::Intern<InnerType>;
impl Display for InnerType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let name = match self {
InnerType::Top => "",
InnerType::Bottom => "",
InnerType::Unit => "()",
InnerType::Bool => "bool",
InnerType::AnyInt => "comptime_int",
InnerType::AnyUInt => "comptime_uint",
InnerType::Str => "str",
InnerType::Int { signed, size } => {
return write!(
f,
"{}{}",
if *signed { "i" } else { "u" },
match size {
IntSize::Bits(bits) => bits.to_string(),
IntSize::Pointer => "size".to_string(),
}
);
}
InnerType::Float { float_type } => match float_type {
FloatType::F32 => "f32",
FloatType::F64 => "f64",
},
InnerType::Pointer { pointee } => {
return write!(f, "*{}", pointee);
}
InnerType::Array { element, size } => {
return write!(f, "[{}; {}]", element, size);
}
InnerType::Function {
return_type,
parameter_types,
} => {
write!(f, "fn(")?;
if let Some((last, rest)) = parameter_types.split_last() {
for param in rest {
write!(f, "{}, ", param)?;
}
write!(f, "{}", last)?;
}
return write!(f, ") -> {}", return_type);
}
InnerType::Tuple { elements } => {
write!(f, "(")?;
if let Some((last, rest)) = elements.split_last() {
for elem in rest {
write!(f, "{}, ", elem)?;
}
write!(f, "{}", last)?;
}
return write!(f, ")");
}
InnerType::TypeUnion { types } => {
if let Some((last, rest)) = types.split_last() {
for ty in rest {
write!(f, "{} | ", ty)?;
}
write!(f, "{}", last)?;
}
return Ok(());
}
InnerType::TypeIntersection { types } => {
if let Some((last, rest)) = types.split_last() {
for ty in rest {
write!(f, "{} ^ ", ty)?;
}
write!(f, "{}", last)?;
}
return Ok(());
}
};
write!(f, "{name}")
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum FloatType { pub enum FloatType {
F32, F32,
@ -108,8 +188,18 @@ pub enum ControlFlowKind {
Continue, Continue,
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] impl ControlFlowKind {
pub struct Index(u32); fn as_str(&self) -> &'static str {
match self {
ControlFlowKind::Return => "RETURN",
ControlFlowKind::Break => "BREAK",
ControlFlowKind::Continue => "CONTINUE",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Index(pub u32);
impl Index { impl Index {
pub fn as_value(self) -> PlaceOrValue { pub fn as_value(self) -> PlaceOrValue {
@ -128,14 +218,7 @@ pub enum AstNode {
File { File {
decls: Vec<Index>, decls: Vec<Index>,
}, },
FunctionProto { ParameterList(ParameterList),
name: String,
return_type: Type,
parameter_list: Index,
},
ParameterList {
parameters: Vec<Index>,
},
Parameter(Parameter), Parameter(Parameter),
FunctionDecl(FunctionDecl), FunctionDecl(FunctionDecl),
Block { Block {
@ -157,7 +240,7 @@ pub enum AstNode {
VarDecl { VarDecl {
mutable: bool, mutable: bool,
name: String, name: String,
var_type: Type, var_type: Option<Type>,
}, },
Assignment { Assignment {
dest: Index, dest: Index,
@ -166,7 +249,7 @@ pub enum AstNode {
GlobalDecl { GlobalDecl {
name: String, name: String,
var_type: Type, var_type: Type,
value: Index, expr: Index,
}, },
StructDecl { StructDecl {
name: String, name: String,
@ -325,6 +408,20 @@ impl PlaceOrValue {
PlaceOrValue::Value(i) => i, PlaceOrValue::Value(i) => i,
} }
} }
pub fn with_index(self, index: Index) -> Self {
match self {
PlaceOrValue::Place(_) => PlaceOrValue::Place(index),
PlaceOrValue::Value(_) => PlaceOrValue::Value(index),
}
}
pub fn eq_placeness(&self, other: &Self) -> bool {
match (self, other) {
(PlaceOrValue::Place(_), PlaceOrValue::Place(_))
| (PlaceOrValue::Value(_), PlaceOrValue::Value(_)) => true,
_ => false,
}
}
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
@ -335,13 +432,9 @@ pub enum Visibility {
} }
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum ParseError<'a> { pub enum ParseError {
#[error("End of file.")] #[error("expected a valid if condition expression")]
EOF, IfCondition,
#[error("Unexpected token: {0:?}")]
UnexpectedToken(Token<'a>),
#[error("Not a type.")]
NotAType,
} }
#[derive(Default, Debug)] #[derive(Default, Debug)]
@ -349,6 +442,14 @@ pub struct Ast {
nodes: Vec<AstNode>, nodes: Vec<AstNode>,
} }
impl core::ops::Index<Index> for Ast {
type Output = AstNode;
fn index(&self, index: Index) -> &Self::Output {
self.nodes.get(index.0 as usize).expect("Invalid AST index")
}
}
impl Ast { impl Ast {
pub fn new() -> Self { pub fn new() -> Self {
Self::default() Self::default()
@ -366,7 +467,7 @@ pub struct FunctionDecl {
name: String, name: String,
visibility: Visibility, visibility: Visibility,
return_type: Type, return_type: Type,
parameter_list: ParameterList, parameter_list: Index,
body: Index, body: Index,
} }
@ -413,7 +514,7 @@ fn new_token_input<'a>(input: &'a str) -> TokenInput<'a> {
IterInput::new(spanned_input, num_bytes..num_bytes) IterInput::new(spanned_input, num_bytes..num_bytes)
} }
fn type_parser<'a, E>() -> impl Parser<'a, TokenInput<'a>, Type, E> fn type_parser<'a, E>() -> impl Parser<'a, TokenInput<'a>, Type, E> + Clone
where where
E: chumsky::extra::ParserExtra<'a, TokenInput<'a>, Error = EmptyErr> + 'a, E: chumsky::extra::ParserExtra<'a, TokenInput<'a>, Error = EmptyErr> + 'a,
{ {
@ -466,17 +567,153 @@ where
}) })
} }
fn visibility<'a>() -> impl Parser<'a, TokenInput<'a>, Visibility, ParserExtra> { fn visibility<'a>() -> impl Parser<'a, TokenInput<'a>, Visibility, ParserExtra> + Clone {
choice((just(Token::Pub).to(Visibility::Public),)) choice((just(Token::Pub).to(Visibility::Public),))
.or_not() .or_not()
.map(|v| v.unwrap_or(Visibility::Private)) .map(|v| v.unwrap_or(Visibility::Private))
} }
fn func_parser<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> { type ParserExtra = chumsky::extra::Full<EmptyErr, SimpleState<Ast>, ()>;
struct ParserCtx<'src, 'b> {
expr: Recursive<Indirect<'src, 'b, TokenInput<'src>, PlaceOrValue, ParserExtra>>,
function: Recursive<Indirect<'src, 'b, TokenInput<'src>, Index, ParserExtra>>,
}
impl<'src, 'b> ParserCtx<'src, 'b>
where
'src: 'b,
{
fn new() -> Self {
let mut this = Self {
expr: Recursive::declare(),
function: Recursive::declare(),
};
let function = this.create_function_decl();
this.function.define(function);
let expr = this.create_expr();
this.expr.define(expr);
this
}
pub fn expr(
&self,
) -> impl Parser<'src, TokenInput<'src>, PlaceOrValue, ParserExtra> + Clone + use<'src, 'b>
{
self.expr.clone()
}
pub fn function(
&self,
) -> impl Parser<'src, TokenInput<'src>, Index, ParserExtra> + Clone + use<'src, 'b> {
self.function.clone()
}
fn var_decl(
&self,
) -> impl Parser<'src, TokenInput<'src>, Index, ParserExtra> + Clone + use<'src, 'b> {
let ident = select! {Token::Ident(ident) => ident};
just(Token::Let)
.ignored()
.then(select! {Token::Mutable => ()}.or_not())
.then(ident)
.then(
just(Token::Colon)
.ignore_then(type_parser::<ParserExtra>())
.or_not(),
)
.then(
just(Token::Equal)
.ignore_then(self.expr().map_with(Self::into_value))
.or_not(),
)
.then_ignore(just(Token::Semi))
.map_with(|((((_, mutable), ident), var_type), val), e: &mut E| {
let decl = e.state().push(AstNode::VarDecl {
mutable: mutable.is_some(),
name: ident.to_string(),
var_type,
});
if let Some(expr) = val {
e.state().push(AstNode::Assignment {
dest: decl,
expr: expr.index(),
})
} else {
decl
}
})
}
fn stmt(
&self,
) -> impl Parser<'src, TokenInput<'src>, Index, ParserExtra> + Clone + use<'src, 'b> {
choice((
self.function.clone(),
self.var_decl(),
self.expr
.clone()
.then_ignore(just(Token::Semi))
.map(PlaceOrValue::index),
))
}
fn simple_expr(
&self,
) -> impl Parser<'src, TokenInput<'src>, PlaceOrValue, ParserExtra> + Clone + use<'src, 'b>
{
let ident = select! {Token::Ident(ident) => ident}.map_with(
|ident, e: &mut MapExtra<TokenInput<'src>, ParserExtra>| {
e.state()
.push(AstNode::UnresolvedDeclRef {
name: ident.to_string(),
})
.as_place()
},
);
let constant = select! {
Token::True => (Intern::new(Value::Bool(true)), Intern::new(InnerType::Bool)),
Token::False => (Intern::new(Value::Bool(false)), Intern::new(InnerType::Bool)),
Token::FloatingConstant(lexeme)|
Token::DotFloatingConstant(lexeme)|
Token::FloatingExpConstant(lexeme)|
Token::DotFloatingExpConstant(lexeme) => {
constants::parse_floating_constant(lexeme)
},
Token::IntegerConstant(lexeme) => {
constants::parse_integer_constant(lexeme, Radix::Dec)
},
tok @ Token::IntegerHexConstant(lexeme)|
tok @ Token::IntegerOctConstant(lexeme)|
tok @ Token::IntegerBinConstant(lexeme) => {
let radix = Radix::from_token(tok).unwrap();
constants::parse_integer_constant(&lexeme[2..], radix)
},
}
.map_with(|(value, ty), e: &mut E| {
e.state().push(AstNode::Constant { ty, value }).as_value()
});
choice((
unit().map(PlaceOrValue::Value),
ident,
constant,
self.expr
.clone()
.delimited_by(just(Token::OpenParens), just(Token::CloseParens)),
self.block(),
))
}
fn create_function_decl(
&self,
) -> impl Parser<'src, TokenInput<'src>, Index, ParserExtra> + Clone + use<'src, 'b> {
let ident = select! {Token::Ident(ident) => ident}; let ident = select! {Token::Ident(ident) => ident};
let param = just(Token::Mutable) let param = select! {Token::Mutable => ()}
.to(())
.or_not() .or_not()
.then(ident) .then(ident)
.then_ignore(just(Token::Colon)) .then_ignore(just(Token::Colon))
@ -495,22 +732,26 @@ fn func_parser<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.delimited_by(just(Token::OpenParens), just(Token::CloseParens)) .delimited_by(just(Token::OpenParens), just(Token::CloseParens))
.labelled("function parameters") .labelled("function parameters")
.map(|params| ParameterList { parameters: params }); .map_with(|params, e: &mut E| {
e.state()
.push(AstNode::ParameterList(ParameterList { parameters: params }))
});
visibility() let ret_type = just(Token::MinusGreater)
.ignore_then(type_parser::<ParserExtra>())
.or_not();
attrs()
.or_not()
.then(visibility())
.then_ignore(just(Token::Fn)) .then_ignore(just(Token::Fn))
.then(ident) .then(ident)
.then(params) .then(params)
// optional return type .then(ret_type)
.then( .then(self.block())
just(Token::MinusGreater) .map_with(|(((((attrs, vis), ident), params), ret), body), e| {
.ignore_then(type_parser())
.or_not(),
)
.then(block())
.map_with(|((((vis, ident), params), ret), body), e| {
e.state().push(AstNode::FunctionDecl(FunctionDecl { e.state().push(AstNode::FunctionDecl(FunctionDecl {
attrs: None, attrs,
name: ident.to_string(), name: ident.to_string(),
visibility: vis, visibility: vis,
return_type: ret.unwrap_or_else(|| Intern::new(InnerType::Unit)), return_type: ret.unwrap_or_else(|| Intern::new(InnerType::Unit)),
@ -520,79 +761,44 @@ fn func_parser<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> {
}) })
} }
type ParserExtra = chumsky::extra::Full<EmptyErr, SimpleState<Ast>, ()>; fn block(
&self,
fn block<'a>() -> impl Parser<'a, TokenInput<'a>, PlaceOrValue, ParserExtra> + Clone { ) -> impl Parser<'src, TokenInput<'src>, PlaceOrValue, ParserExtra> + Clone + use<'src, 'b>
just(Token::OpenBrace) {
.ignored() self.stmt()
.then_ignore(just(Token::CloseBrace)) .repeated()
.map_with(|_, e: &mut MapExtra<'_, '_, _, ParserExtra>| { .collect::<Vec<_>>()
e.state() .then(self.expr.clone().or_not())
.push(AstNode::Block { .delimited_by(just(Token::OpenBrace), just(Token::CloseBrace))
statements: vec![], .map_with(|(statements, expr), e: &mut E| {
expr: None, expr.unwrap_or(PlaceOrValue::Value(Index(u32::MAX)))
.with_index(e.state().push(AstNode::Block {
statements,
expr: expr.map(PlaceOrValue::index),
}))
}) })
}
fn into_value(idx: PlaceOrValue, e: &mut E) -> PlaceOrValue {
match idx {
PlaceOrValue::Place(index) => e.state().push(AstNode::PlaceToValue { expr: index }),
PlaceOrValue::Value(index) => index,
}
.as_value() .as_value()
// TODO: add statements and expr and map placeness by expr
})
} }
fn unit<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> + Clone { fn into_place(idx: PlaceOrValue, e: &mut E) -> PlaceOrValue {
just(Token::OpenParens) match idx {
.ignored() PlaceOrValue::Value(index) => e.state().push(AstNode::ValueToPlace { expr: index }),
.ignore_then(just(Token::CloseParens)) PlaceOrValue::Place(index) => index,
.map_with(|_, e: &mut MapExtra<TokenInput<'a>, ParserExtra>| {
e.state().push(AstNode::Constant {
ty: Intern::new(InnerType::Unit),
value: Intern::new(Value::Unit),
})
})
} }
type E<'a, 'b> = MapExtra<'a, 'b, TokenInput<'a>, ParserExtra>;
fn simple_expr<'a, 'b>(
expr: Recursive<Direct<'a, 'b, TokenInput<'a>, PlaceOrValue, ParserExtra>>,
) -> impl Parser<'a, TokenInput<'a>, PlaceOrValue, ParserExtra> + Clone {
let ident = select! {Token::Ident(ident) => ident}.map_with(
|ident, e: &mut MapExtra<TokenInput<'a>, ParserExtra>| {
e.state()
.push(AstNode::UnresolvedDeclRef {
name: ident.to_string(),
})
.as_place() .as_place()
},
);
let constant = select! {
Token::FloatingConstant(lexeme)|
Token::DotFloatingConstant(lexeme)|
Token::FloatingExpConstant(lexeme)|
Token::DotFloatingExpConstant(lexeme) => {
constants::parse_floating_constant(lexeme)
},
Token::IntegerConstant(lexeme) => {
constants::parse_integer_constant(lexeme, Radix::Dec)
},
tok @ Token::IntegerHexConstant(lexeme)|
tok @ Token::IntegerOctConstant(lexeme)|
tok @ Token::IntegerBinConstant(lexeme) => {
let radix = Radix::from_token(tok).unwrap();
constants::parse_integer_constant(&lexeme[2..], radix)
},
}
.map_with(|(value, ty), e: &mut E| e.state().push(AstNode::Constant { ty, value }).as_value());
choice((
unit().map(PlaceOrValue::Value),
ident,
constant,
expr.delimited_by(just(Token::OpenParens), just(Token::CloseParens)),
block(),
))
} }
fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, PlaceOrValue, ParserExtra> { fn create_expr(
&'_ self,
) -> impl Parser<'src, TokenInput<'src>, PlaceOrValue, ParserExtra> + Clone + use<'src, 'b>
{
let assignment = choice(( let assignment = choice((
just(Token::Equal), just(Token::Equal),
just(Token::PlusEqual), just(Token::PlusEqual),
@ -637,25 +843,8 @@ fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, PlaceOrValue, ParserExtra> {
let r#as = just(Token::As).ignore_then(type_parser::<ParserExtra>()); let r#as = just(Token::As).ignore_then(type_parser::<ParserExtra>());
fn into_value(idx: PlaceOrValue, e: &mut E) -> PlaceOrValue {
match idx {
PlaceOrValue::Place(index) => e.state().push(AstNode::PlaceToValue { expr: index }),
PlaceOrValue::Value(index) => index,
}
.as_value()
}
fn into_place(idx: PlaceOrValue, e: &mut E) -> PlaceOrValue {
match idx {
PlaceOrValue::Value(index) => e.state().push(AstNode::ValueToPlace { expr: index }),
PlaceOrValue::Place(index) => index,
}
.as_place()
}
// TODO: postfix: function call, field access, array subscript // TODO: postfix: function call, field access, array subscript
recursive(move |_expr| { let _expr = self.expr.clone();
let simple = simple_expr(_expr.clone());
let subscript = _expr let subscript = _expr
.clone() .clone()
@ -664,12 +853,12 @@ fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, PlaceOrValue, ParserExtra> {
just(Token::CloseSquareBracket), just(Token::CloseSquareBracket),
) )
// subscript takes a value as the index // subscript takes a value as the index
.map_with(into_value); .map_with(Self::into_value);
let arguments = _expr let arguments = _expr
.clone() .clone()
// arguments take values // arguments take values
.map_with(into_value) .map_with(Self::into_value)
.map(PlaceOrValue::index) .map(PlaceOrValue::index)
.separated_by(just(Token::Comma)) .separated_by(just(Token::Comma))
.allow_trailing() .allow_trailing()
@ -678,10 +867,10 @@ fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, PlaceOrValue, ParserExtra> {
let field = just(Token::Dot).ignore_then(select! {Token::Ident(ident) => ident}); let field = just(Token::Dot).ignore_then(select! {Token::Ident(ident) => ident});
let assignment_expr = simple.pratt(( let assignment_expr = self.simple_expr().pratt((
postfix(100, subscript, |expr, index: PlaceOrValue, e: &mut E| { postfix(100, subscript, |expr, index: PlaceOrValue, e: &mut E| {
let node = AstNode::Subscript { let node = AstNode::Subscript {
expr: into_value(expr, e).index(), expr: Self::into_value(expr, e).index(),
index: index.index(), index: index.index(),
}; };
// subscript yields a place // subscript yields a place
@ -689,7 +878,7 @@ fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, PlaceOrValue, ParserExtra> {
}), }),
postfix(100, arguments, |callee, arguments, e: &mut E| { postfix(100, arguments, |callee, arguments, e: &mut E| {
let node = AstNode::CallExpr { let node = AstNode::CallExpr {
callee: into_value(callee, e).index(), callee: Self::into_value(callee, e).index(),
arguments, arguments,
}; };
// function call yields a value // function call yields a value
@ -697,7 +886,7 @@ fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, PlaceOrValue, ParserExtra> {
}), }),
postfix(100, field, |expr, field: &str, e: &mut E| { postfix(100, field, |expr, field: &str, e: &mut E| {
let node = AstNode::FieldAccess { let node = AstNode::FieldAccess {
expr: into_place(expr, e).index(), expr: Self::into_place(expr, e).index(),
field: field.to_string(), field: field.to_string(),
}; };
// field access yields a place // field access yields a place
@ -705,15 +894,15 @@ fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, PlaceOrValue, ParserExtra> {
}), }),
postfix(99, r#as, |expr, ty, e: &mut E| { postfix(99, r#as, |expr, ty, e: &mut E| {
let node = AstNode::ExplicitCast { let node = AstNode::ExplicitCast {
expr: into_value(expr, e).index(), expr: Self::into_value(expr, e).index(),
ty, ty,
}; };
e.state().push(node).as_value() e.state().push(node).as_value()
}), }),
prefix(95, prefixes, |op, expr, e: &mut E| { prefix(95, prefixes, |op, expr, e: &mut E| {
let node = match op { let node = match op {
Token::Bang => AstNode::Not(into_value(expr, e).index()), Token::Bang => AstNode::Not(Self::into_value(expr, e).index()),
Token::Minus => AstNode::Negate(into_value(expr, e).index()), Token::Minus => AstNode::Negate(Self::into_value(expr, e).index()),
Token::Star => { Token::Star => {
return e return e
.state() .state()
@ -721,15 +910,15 @@ fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, PlaceOrValue, ParserExtra> {
.as_place(); .as_place();
} }
Token::Ampersand => AstNode::AddressOf { Token::Ampersand => AstNode::AddressOf {
expr: into_place(expr, e).index(), expr: Self::into_place(expr, e).index(),
}, },
_ => unreachable!(), _ => unreachable!(),
}; };
e.state().push(node).as_value() e.state().push(node).as_value()
}), }),
infix(left(90), multiplicative, |left, op, right, e: &mut E| { infix(left(90), multiplicative, |left, op, right, e: &mut E| {
let left = into_value(left, e).index(); let left = Self::into_value(left, e).index();
let right = into_value(right, e).index(); let right = Self::into_value(right, e).index();
let node = match op { let node = match op {
Token::Star => AstNode::Multiply { left, right }, Token::Star => AstNode::Multiply { left, right },
Token::Slash => AstNode::Divide { left, right }, Token::Slash => AstNode::Divide { left, right },
@ -739,8 +928,8 @@ fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, PlaceOrValue, ParserExtra> {
e.state().push(node).as_value() e.state().push(node).as_value()
}), }),
infix(left(80), additive, |left, op, right, e: &mut E| { infix(left(80), additive, |left, op, right, e: &mut E| {
let left = into_value(left, e).index(); let left = Self::into_value(left, e).index();
let right = into_value(right, e).index(); let right = Self::into_value(right, e).index();
let node = match op { let node = match op {
Token::Plus => AstNode::Add { left, right }, Token::Plus => AstNode::Add { left, right },
Token::Minus => AstNode::Subtract { left, right }, Token::Minus => AstNode::Subtract { left, right },
@ -749,8 +938,8 @@ fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, PlaceOrValue, ParserExtra> {
e.state().push(node).as_value() e.state().push(node).as_value()
}), }),
infix(left(70), shift, |left, op, right, e: &mut E| { infix(left(70), shift, |left, op, right, e: &mut E| {
let left = into_value(left, e).index(); let left = Self::into_value(left, e).index();
let right = into_value(right, e).index(); let right = Self::into_value(right, e).index();
let node = match op { let node = match op {
Token::LessLess => AstNode::ShiftLeft { left, right }, Token::LessLess => AstNode::ShiftLeft { left, right },
Token::GreaterGreater => AstNode::ShiftRight { left, right }, Token::GreaterGreater => AstNode::ShiftRight { left, right },
@ -759,8 +948,8 @@ fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, PlaceOrValue, ParserExtra> {
e.state().push(node).as_value() e.state().push(node).as_value()
}), }),
infix(left(60), relational, |left, op, right, e: &mut E| { infix(left(60), relational, |left, op, right, e: &mut E| {
let left = into_value(left, e).index(); let left = Self::into_value(left, e).index();
let right = into_value(right, e).index(); let right = Self::into_value(right, e).index();
let node = match op { let node = match op {
Token::Less => AstNode::Less { left, right }, Token::Less => AstNode::Less { left, right },
Token::LessEqual => AstNode::LessEq { left, right }, Token::LessEqual => AstNode::LessEq { left, right },
@ -771,8 +960,8 @@ fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, PlaceOrValue, ParserExtra> {
e.state().push(node).as_value() e.state().push(node).as_value()
}), }),
infix(left(50), equality, |left, op, right, e: &mut E| { infix(left(50), equality, |left, op, right, e: &mut E| {
let left = into_value(left, e).index(); let left = Self::into_value(left, e).index();
let right = into_value(right, e).index(); let right = Self::into_value(right, e).index();
let node = match op { let node = match op {
Token::EqualEqual => AstNode::Eq { left, right }, Token::EqualEqual => AstNode::Eq { left, right },
Token::BangEqual => AstNode::NotEq { left, right }, Token::BangEqual => AstNode::NotEq { left, right },
@ -781,42 +970,42 @@ fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, PlaceOrValue, ParserExtra> {
e.state().push(node).as_value() e.state().push(node).as_value()
}), }),
infix(left(40), and, |left, _op, right, e: &mut E| { infix(left(40), and, |left, _op, right, e: &mut E| {
let left = into_value(left, e).index(); let left = Self::into_value(left, e).index();
let right = into_value(right, e).index(); let right = Self::into_value(right, e).index();
let node = AstNode::BitAnd { left, right }; let node = AstNode::BitAnd { left, right };
e.state().push(node).as_value() e.state().push(node).as_value()
}), }),
infix(left(30), xor, |left, _op, right, e: &mut E| { infix(left(30), xor, |left, _op, right, e: &mut E| {
let left = into_value(left, e).index(); let left = Self::into_value(left, e).index();
let right = into_value(right, e).index(); let right = Self::into_value(right, e).index();
let node = AstNode::BitXor { left, right }; let node = AstNode::BitXor { left, right };
e.state().push(node).as_value() e.state().push(node).as_value()
}), }),
infix(left(20), or, |left, _op, right, e: &mut E| { infix(left(20), or, |left, _op, right, e: &mut E| {
let left = into_value(left, e).index(); let left = Self::into_value(left, e).index();
let right = into_value(right, e).index(); let right = Self::into_value(right, e).index();
let node = AstNode::BitOr { left, right }; let node = AstNode::BitOr { left, right };
e.state().push(node).as_value() e.state().push(node).as_value()
}), }),
infix(left(10), logical_and, |left, _op, right, e: &mut E| { infix(left(10), logical_and, |left, _op, right, e: &mut E| {
let left = into_value(left, e).index(); let left = Self::into_value(left, e).index();
let right = into_value(right, e).index(); let right = Self::into_value(right, e).index();
let node = AstNode::LogicalAnd { left, right }; let node = AstNode::LogicalAnd { left, right };
e.state().push(node).as_value() e.state().push(node).as_value()
}), }),
infix(left(5), logical_or, |left, _op, right, e: &mut E| { infix(left(5), logical_or, |left, _op, right, e: &mut E| {
let left = into_value(left, e).index(); let left = Self::into_value(left, e).index();
let right = into_value(right, e).index(); let right = Self::into_value(right, e).index();
let node = AstNode::LogicalOr { left, right }; let node = AstNode::LogicalOr { left, right };
e.state().push(node).as_value() e.state().push(node).as_value()
}), }),
infix(right(1), assignment, |left, op, right, e: &mut E| { infix(right(1), assignment, |left, op, right, e: &mut E| {
let dest = into_place(left, e).index(); let dest = Self::into_place(left, e).index();
let right = into_value(right, e).index(); let right = Self::into_value(right, e).index();
let node = if op == Token::Equal { let node = if op == Token::Equal {
AstNode::Assignment { dest, expr: right } AstNode::Assignment { dest, expr: right }
} else { } else {
let left = into_value(left, e).index(); let left = Self::into_value(left, e).index();
let right = match op { let right = match op {
Token::PlusEqual => e.state().push(AstNode::Add { left, right }), Token::PlusEqual => e.state().push(AstNode::Add { left, right }),
Token::MinusEqual => e.state().push(AstNode::Subtract { left, right }), Token::MinusEqual => e.state().push(AstNode::Subtract { left, right }),
@ -838,41 +1027,128 @@ fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, PlaceOrValue, ParserExtra> {
}), }),
)); ));
let else_expr = just(Token::Else).ignore_then(_expr.clone()); let expr = choice((self.if_else_expr(), assignment_expr)).labelled("expression");
let if_expr = just(Token::If) expr
}
fn if_else_expr(
&self,
) -> impl Parser<'src, TokenInput<'src>, PlaceOrValue, ParserExtra> + Clone + use<'src, 'b>
{
let else_expr = just(Token::Else).ignore_then(self.expr());
just(Token::If)
.ignore_then( .ignore_then(
_expr self.expr()
.clone() .map_with(Self::into_value)
.map_with(into_value)
.map(PlaceOrValue::index) .map(PlaceOrValue::index)
.delimited_by(just(Token::OpenParens), just(Token::CloseParens)), .delimited_by(just(Token::OpenParens), just(Token::CloseParens))
.recover_with(via_parser({
// parenthised recovery:
recursive(|recovery| {
just(Token::OpenParens)
.ignored()
.ignore_then(choice((
none_of([Token::CloseParens, Token::OpenParens]).map(|_| ()),
recovery.map(|_| ()),
)))
.repeated()
.then_ignore(just(Token::CloseParens))
})
.map_with(|_, e: &mut E| {
e.state().push(AstNode::Error {
err: Box::new(ParseError::IfCondition),
})
})
})),
) )
.then(_expr.clone()) .then(self.expr())
.then(else_expr.or_not()) .then(else_expr.or_not())
.map_with(|((condition, then), or), e: &mut E| { .map_with(|((condition, then), or), e: &mut E| {
// TODO: determine placeness from branches use PlaceOrValue::*;
let (then, or) = match (then, or) {
(Place(then), Some(Place(or))) => (Place(then), Some(Place(or))),
_ => (
Self::into_value(then, e),
or.map(|or| Self::into_value(or, e)),
),
};
let node = AstNode::If { let node = AstNode::If {
condition, condition,
then: then.index(), then: then.index(),
r#else: or.map(PlaceOrValue::index), r#else: or.map(PlaceOrValue::index),
}; };
e.state().push(node).as_value() then.with_index(e.state().push(node))
});
let expr = choice((if_expr, assignment_expr)).labelled("expression");
Arc::new(expr)
}) })
} }
fn global_decl(&self) -> impl Parser<'src, TokenInput<'src>, Index, ParserExtra> + Clone {
let ident = select! {Token::Ident(ident) => ident};
attrs()
.or_not()
.then(visibility())
.then_ignore(just(Token::Let))
.then(ident)
.then_ignore(just(Token::Colon))
.then(type_parser::<ParserExtra>())
.then_ignore(just(Token::Equal))
.then(self.expr.clone())
.then_ignore(just(Token::Semi))
.map_with(|((((_attrs, _vis), name), var_type), value), e| {
e.state().push(AstNode::GlobalDecl {
name: name.to_string(),
var_type,
expr: value.index(),
})
})
}
fn file(&self) -> impl Parser<'src, TokenInput<'src>, Index, ParserExtra> + Clone {
choice((self.function.clone(), self.global_decl()))
.repeated()
.collect::<Vec<_>>()
.map_with(|decls, e: &mut E| e.state().push(AstNode::File { decls }))
}
}
fn unit<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> + Clone {
just(Token::OpenParens)
.ignored()
.ignore_then(just(Token::CloseParens))
.map_with(|_, e: &mut MapExtra<TokenInput<'a>, ParserExtra>| {
e.state().push(AstNode::Constant {
ty: Intern::new(InnerType::Unit),
value: Intern::new(Value::Unit),
})
})
}
type E<'a, 'b> = MapExtra<'a, 'b, TokenInput<'a>, ParserExtra>;
fn attrs<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> + Clone {
let docs = select! { Token::DocComment(doc) => doc }.map_with(|doc, e: &mut E| {
e.state().push(AstNode::Doc {
text: doc.to_string(),
})
});
docs.repeated()
.at_least(1)
.collect::<Vec<_>>()
.map_with(|attrs, e: &mut E| e.state().push(AstNode::Attributes { attrs }))
}
mod constants; mod constants;
mod pretty;
mod symbols;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use chumsky::{Parser, extra::SimpleState}; use chumsky::{ParseResult, Parser, extra::SimpleState};
use crate::{Ast, AstNode, new_token_input, type_parser}; use crate::{Ast, AstNode, ParserCtx, ParserExtra, new_token_input, pretty, type_parser};
#[test] #[test]
fn print_ast_node_size() { fn print_ast_node_size() {
@ -932,16 +1208,91 @@ mod tests {
); );
} }
fn print_ast<'src, T>(
tokens: crate::TokenInput<'src>,
parser: impl Parser<'src, crate::TokenInput<'src>, T, ParserExtra>,
) {
let mut state = SimpleState(Ast::new());
let out = parser.parse_with_state(tokens, &mut state);
for e in out.errors() {
eprintln!("Error: {}", e);
panic!("errors occured while parsing.")
}
let ast = state.0;
let mut pretty = pretty::PrettyPrint::new();
pretty.print(&ast);
}
#[test] #[test]
fn parse_exprs() { fn parse_exprs() {
let print_ast = |tokens| { let ctx = crate::ParserCtx::new();
let mut state = SimpleState(Ast::new());
let out = crate::expr().parse_with_state(tokens, &mut state).unwrap();
eprintln!("{:?}", state.0);
};
print_ast(new_token_input("()")); print_ast(new_token_input("true"), ctx.expr());
print_ast(new_token_input("!() as i32")); }
print_ast(new_token_input("1 << 2 & 3"));
#[test]
fn parse_fns() {
let ctx = crate::ParserCtx::new();
print_ast(
new_token_input(
r#"
/// docs!
fn my_function(a: i32, b: *const u8) -> i32 {
let mut x: i32;
x = a + 1;
x
}
"#,
),
ctx.function(),
);
}
#[test]
fn parse_var_decl() {
let ctx = crate::ParserCtx::new();
print_ast(
new_token_input(
r#"
let mut x: i32 = 10;
"#,
),
ctx.var_decl(),
);
}
#[test]
fn parse_stmts() {
let ctx = crate::ParserCtx::new();
print_ast(
new_token_input(
r#"
let mut x: i32 = 10;
"#,
),
ctx.stmt(),
);
print_ast(
new_token_input(
r#"
(if (true) {x} else {y}) = x + x;
"#,
),
ctx.stmt(),
);
}
#[test]
fn parse_if_expr() {
let ctx = crate::ParserCtx::new();
print_ast(
new_token_input(
r#"
if (true) 1 / 2 else true
"#,
),
ctx.if_else_expr(),
);
} }
} }

398
crates/parser/src/pretty.rs Normal file
View file

@ -0,0 +1,398 @@
use crate::{Ast, AstNode, Index};
pub struct PrettyPrint {
lines: Vec<String>,
indents: Vec<Indent>,
}
const VERTICAL: &str = "";
const HORIZONTAL: &str = "";
const CONNECTOR: &str = "";
const END_CONNECTOR: &str = "";
const EMPTY: &str = " ";
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
enum Indent {
Vertical,
End,
Empty,
}
impl PrettyPrint {
pub fn new() -> Self {
Self {
lines: Vec::new(),
indents: Vec::new(),
}
}
fn push_line(&mut self, line: String) {
let (last, rest) = self
.indents
.split_last_mut()
.map_or::<(Option<&mut Indent>, &mut [Indent]), _>((None, &mut []), |(last, rest)| {
(Some(last), rest)
});
let rest = rest.iter_mut().map(|indent| match *indent {
Indent::Vertical => VERTICAL,
Indent::End => {
*indent = Indent::Empty;
END_CONNECTOR
}
Indent::Empty => EMPTY,
});
let last = if let Some(last) = last {
match last {
Indent::Vertical => CONNECTOR,
Indent::End => {
*last = Indent::Empty;
END_CONNECTOR
}
Indent::Empty => CONNECTOR,
}
} else {
""
};
self.lines.push(
rest.chain(std::iter::once(last))
.chain(std::iter::once(line.as_str()))
.collect::<String>(),
);
}
pub fn print(mut self, ast: &Ast) {
let root = ast.nodes.len().checked_sub(1).unwrap();
self.stuff(ast, Index(root as u32));
for line in self.lines {
println!("{}", line);
}
}
fn with_indent<I>(
&mut self,
mut items: impl DoubleEndedIterator<Item = I>,
mut f: impl FnMut(&mut Self, I),
) {
if let Some(last) = (&mut items).next_back() {
self.indents.push(Indent::Vertical);
for item in items {
f(self, item);
}
*self.indents.last_mut().unwrap() = Indent::End;
f(self, last);
self.indents.pop();
}
}
fn stuff(&mut self, ast: &Ast, node: Index) {
let mut node = ast.nodes.get(node.0 as usize).unwrap();
match node {
AstNode::Root { files } => {
self.push_line(format!(
"{} {{num_files: {}}}",
node_name(node),
files.len()
));
self.with_indent(files.iter(), |this, idx| {
this.stuff(ast, *idx);
});
}
AstNode::File { decls } => {
self.push_line(format!(
"{} {{num_decls: {}}}",
node_name(node),
decls.len()
));
self.with_indent(decls.iter(), |this, idx| {
this.stuff(ast, *idx);
});
}
AstNode::ParameterList(parameters) => {
self.push_line(format!(
"{}[{}]",
node_name(node),
parameters.parameters.len()
));
self.with_indent(parameters.parameters.iter(), |this, idx| {
this.stuff(ast, *idx);
});
}
AstNode::Parameter(parameter) => {
self.push_line(format!(
"{} [{}: {}]",
node_name(node),
parameter.name,
parameter.param_type
));
}
AstNode::FunctionDecl(function_decl) => {
self.push_line(format!("{} {}", node_name(node), function_decl.name,));
self.indents.push(Indent::Vertical);
self.push_line(format!("VISIBILITY: {:?}", function_decl.visibility));
self.stuff(ast, function_decl.parameter_list);
self.push_line(format!("RETURN_TYPE: {}", function_decl.return_type));
*self.indents.last_mut().unwrap() = Indent::End;
self.stuff(ast, function_decl.body);
self.indents.pop();
}
AstNode::Block { statements, expr } => {
self.push_line(format!("{}", node_name(node),));
self.with_indent(statements.iter().chain(expr), |this, idx| {
this.stuff(ast, *idx);
});
}
AstNode::Constant { ty, value } => {
self.push_line(format!("{} [{} := {:?}]", node_name(node), ty, value));
}
AstNode::NoopExpr => {
self.push_line(format!("{}", node_name(node),));
}
AstNode::Stmt { expr } => {
self.push_line(format!("{}", node_name(node),));
self.indents.push(Indent::End);
self.stuff(ast, *expr);
self.indents.pop();
}
AstNode::ControlFlow { kind, expr } => todo!(),
AstNode::VarDecl {
mutable,
name,
var_type,
} => {
self.push_line(format!(
"{} [{} {}: {}]",
node_name(node),
name,
mutable.then_some(" mut").unwrap_or(""),
var_type.map_or("?".to_string(), |ty| format!("{ty}"))
));
}
AstNode::Assignment { dest, expr } => {
self.push_line(format!("{}", node_name(node),));
self.indents.push(Indent::Vertical);
self.push_line("DEST".to_string());
self.with_indent(core::iter::once(*dest), |this, idx| {
this.stuff(ast, idx);
});
*self.indents.last_mut().unwrap() = Indent::End;
self.push_line("EXPR".to_string());
self.with_indent(core::iter::once(*expr), |this, idx| {
this.stuff(ast, idx);
});
self.indents.pop();
}
AstNode::GlobalDecl {
name,
var_type,
expr,
} => {
self.push_line(format!("{} [{}: {}]", node_name(node), name, var_type));
self.with_indent(core::iter::once(*expr), |this, idx| {
this.stuff(ast, idx);
});
}
AstNode::StructDecl { name, fields } => todo!(),
AstNode::FieldDecl { name, field_type } => todo!(),
AstNode::FieldAccess { expr, field } => todo!(),
AstNode::UnresolvedDeclRef { name } => {
self.push_line(format!("{} \"{}\"", node_name(node), name,));
}
AstNode::DeclRef { decl } => {
self.push_line(format!("{} @{}", node_name(node), decl.0,));
}
AstNode::TypeDeclRef { ty } => {
self.push_line(format!("{} @{:?}", node_name(node), ty,));
}
AstNode::ExplicitCast { expr, ty } => {
self.push_line(format!("{} {}", node_name(node), ty,));
self.indents.push(Indent::End);
self.stuff(ast, *expr);
self.indents.pop();
}
AstNode::Not(expr)
| AstNode::Negate(expr)
| AstNode::Deref { expr }
| AstNode::AddressOf { expr }
| AstNode::ValueToPlace { expr }
| AstNode::PlaceToValue { expr } => {
self.push_line(format!("{}", node_name(node),));
self.indents.push(Indent::End);
self.stuff(ast, *expr);
self.indents.pop();
}
AstNode::CallExpr { callee, arguments } => {
self.push_line(format!(
"{} {{num_args: {}}}",
node_name(node),
arguments.len()
));
self.indents.push(Indent::Vertical);
self.stuff(ast, *callee);
*self.indents.last_mut().unwrap() = Indent::End;
self.with_indent(arguments.iter(), |this, arg| {
this.stuff(ast, *arg);
});
self.indents.pop();
}
AstNode::Argument { expr } => {
self.stuff(ast, *expr);
}
AstNode::Multiply { left, right }
| AstNode::Divide { left, right }
| AstNode::Modulus { left, right }
| AstNode::Add { left, right }
| AstNode::Subtract { left, right }
| AstNode::BitOr { left, right }
| AstNode::BitAnd { left, right }
| AstNode::BitXor { left, right }
| AstNode::LogicalOr { left, right }
| AstNode::LogicalAnd { left, right }
| AstNode::Eq { left, right }
| AstNode::NotEq { left, right }
| AstNode::Less { left, right }
| AstNode::LessEq { left, right }
| AstNode::Greater { left, right }
| AstNode::GreaterEq { left, right }
| AstNode::ShiftLeft { left, right }
| AstNode::ShiftRight { left, right } => {
self.push_line(format!("{}", node_name(node),));
self.with_indent([*left, *right].into_iter(), |this, idx| {
this.stuff(ast, idx);
});
}
AstNode::Subscript { expr, index } => {
self.push_line(format!("{}", node_name(node),));
self.indents.push(Indent::Vertical);
self.stuff(ast, *expr);
*self.indents.last_mut().unwrap() = Indent::End;
self.push_line("INDEX".to_string());
self.with_indent([*index].into_iter(), |this, idx| {
this.stuff(ast, idx);
});
self.indents.pop();
}
AstNode::If {
condition,
then,
r#else,
} => {
self.push_line(format!("{}", node_name(node),));
self.indents.push(Indent::Vertical);
self.push_line("COND".to_string());
self.with_indent([*condition].into_iter(), |this, idx| {
this.stuff(ast, idx);
});
self.push_line("THEN".to_string());
if let Some(r#else) = r#else {
self.with_indent(core::iter::once(*then), |this, idx| {
this.stuff(ast, idx);
});
*self.indents.last_mut().unwrap() = Indent::End;
self.push_line("ELSE".to_string());
self.with_indent(core::iter::once(*r#else), |this, idx| {
this.stuff(ast, idx);
});
} else {
*self.indents.last_mut().unwrap() = Indent::End;
self.with_indent(core::iter::once(*then), |this, idx| {
this.stuff(ast, idx);
});
}
self.indents.pop();
}
AstNode::Else { expr } => {
self.push_line(format!("{}", node_name(node),));
self.indents.push(Indent::End);
self.stuff(ast, *expr);
self.indents.pop();
}
AstNode::Comment { text } => {
self.push_line(format!("{} \"{}\"", node_name(node), text,));
}
AstNode::Attributes { attrs } => {
self.push_line(format!(
"{} {{num_attrs: {}}}",
node_name(node),
attrs.len()
));
self.with_indent(attrs.iter(), |this, &attr| {
this.stuff(ast, attr);
});
}
AstNode::Doc { text } => {
self.push_line(format!("{} \"{}\"", node_name(node), text,));
}
AstNode::Error { err } => {
self.push_line(format!("{} \"{}\"", node_name(node), err,));
}
}
}
}
fn node_name(node: &AstNode) -> &'static str {
match node {
AstNode::Root { .. } => "ROOT",
AstNode::File { .. } => "FILE",
AstNode::ParameterList(_) => "PARAMS",
AstNode::Parameter(_) => "PARAM",
AstNode::FunctionDecl(_) => "FN",
AstNode::Block { .. } => "BLOCK",
AstNode::Constant { .. } => "CONSTANT",
AstNode::NoopExpr => "NOOP",
AstNode::Stmt { .. } => "STMT",
AstNode::ControlFlow { .. } => "CONTROL_FLOW",
AstNode::VarDecl { .. } => "VAR_DECL",
AstNode::Assignment { .. } => "ASSIGN",
AstNode::GlobalDecl { .. } => "GLOBAL_DECL",
AstNode::StructDecl { .. } => "STRUCT",
AstNode::FieldDecl { .. } => "FIELD",
AstNode::FieldAccess { .. } => "FIELD_ACCESS",
AstNode::UnresolvedDeclRef { .. } => "UNRESOLVED_DECL_REF",
AstNode::DeclRef { .. } => "DECL_REF",
AstNode::TypeDeclRef { .. } => "TYPE_REF",
AstNode::ExplicitCast { .. } => "AS",
AstNode::Deref { .. } => "DEREF",
AstNode::AddressOf { .. } => "ADDR_OF",
AstNode::PlaceToValue { .. } => "INTO_VALUE",
AstNode::ValueToPlace { .. } => "INTO_PLACE",
AstNode::CallExpr { .. } => "CALL",
AstNode::Argument { .. } => "ARG",
AstNode::Not(_) => "NOT",
AstNode::Negate(_) => "NEGATE",
AstNode::Multiply { .. } => "MUL",
AstNode::Divide { .. } => "DIV",
AstNode::Modulus { .. } => "REM",
AstNode::Add { .. } => "ADD",
AstNode::Subtract { .. } => "SUB",
AstNode::BitOr { .. } => "BIT_OR",
AstNode::BitAnd { .. } => "BIT_AND",
AstNode::BitXor { .. } => "BIT_XOR",
AstNode::LogicalOr { .. } => "OR",
AstNode::LogicalAnd { .. } => "AND",
AstNode::Eq { .. } => "EQ",
AstNode::NotEq { .. } => "NEQ",
AstNode::Less { .. } => "LT",
AstNode::LessEq { .. } => "LEQ",
AstNode::Greater { .. } => "GT",
AstNode::GreaterEq { .. } => "GEQ",
AstNode::ShiftLeft { .. } => "SHL",
AstNode::ShiftRight { .. } => "SHR",
AstNode::Subscript { .. } => "SUBSCRIPT",
AstNode::If { .. } => "IF",
AstNode::Else { .. } => "ELSE",
AstNode::Comment { .. } => "COMMENT",
AstNode::Attributes { .. } => "META",
AstNode::Doc { .. } => "DOCS",
AstNode::Error { .. } => "ERR",
}
}

View file

@ -0,0 +1,178 @@
//! Coming from the ast, we have a `DeclRef` with an interned identifier `ident`
//! and want to find the symbol it refers to.
//!
//! To help, we have a struct keeping track of all accessible scopes. Now, we
//! want to look through any accessible scope `s` for a symbol with the name
//! `ident`. Thus: `Symbol {scope: `s`, name: `ident`, ..}`.
//!
//! We might also know the type of the symbol we are looking for, if we want
//! to permit fields/variables and methods/functions sharing names.
//!
//! Since I want to allow variable shadowing for local variables, some strategy
//! to differentiate between shadowed variables must be employed:
//! - keys of type SymbolKind::Local might point to a list of values with source locations
//! - keys might contain source locations.
//!
//! Any symbol pointed at from within the ast must again point at an ast
//! object.
//! Thus: `Key` -> `AstIndex`
//! Exception: `Key::ScopeByIndex` -> `InternIndex`
use core::fmt::Debug;
use std::collections::BTreeMap;
use internment::Intern;
use crate::Index;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Span(u32);
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Spanned<T>(pub T, Span);
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum SymbolKind {
__First,
Const,
Function,
Type,
__TypeScope,
Scope,
ParentScope,
Parameter(Span),
Local(Span),
__Last,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Key {
ScopeByName {
name: Intern<str>,
},
/// not all scopes have a name, as some are anonymous blocks or otherwise nameless
ScopeByIndex {
ast: Index,
},
Symbol {
scope: Index,
name: Intern<str>,
kind: SymbolKind,
},
}
impl Key {
pub fn parent(scope: Index) -> Key {
Key::Symbol {
scope,
name: Intern::from(""),
kind: SymbolKind::ParentScope,
}
}
}
#[derive(Clone, Copy, Debug)]
pub enum Payload {
Ast(Index),
Name(Intern<str>),
}
pub struct Symbols {
inner: BTreeMap<Key, Payload>,
}
impl Debug for Symbols {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Symbols [")?;
if f.alternate() {
writeln!(f, "")?;
}
let entries = self.inner.iter();
f.debug_list().entries(entries).finish()?;
write!(f, "]")?;
if f.alternate() {
writeln!(f, "")?;
}
Ok(())
}
}
// checks for each scope in scopes_in_tree Symbol { scope, kind: SymbolKind::Local, 0}..Symbol { scope, kind: SymbolKind::Scope, u32::MAX}
struct SymbolTreePos {
scopes_in_scope: Vec<Index>,
}
impl Symbols {
pub fn new() -> Symbols {
Self {
inner: BTreeMap::new(),
}
}
pub fn insert_scope(&mut self, name: Intern<str>, ast: Index) {
self.inner
.insert(Key::ScopeByIndex { ast }, Payload::Name(name));
self.inner
.insert(Key::ScopeByName { name }, Payload::Ast(ast));
}
pub fn find_symbol(&self, scope: Index, name: Intern<str>, loc: Span) -> Option<(Key, Index)> {
use SymbolKind::*;
let range = self.inner.range(
Key::Symbol {
scope,
name,
kind: __First,
}..=Key::Symbol {
scope,
name,
kind: Local(loc),
},
);
if let Some((&key, &Payload::Ast(index))) = range.rev().next() {
Some((key, index))
} else {
if let Some(&Payload::Ast(parent)) = self.inner.get(&Key::parent(scope)) {
self.find_symbol(parent, name, loc)
} else {
None
}
}
}
pub fn find_type_symbol(
&self,
scope: Index,
name: Intern<str>,
loc: Span,
) -> Option<(Key, Index)> {
use SymbolKind::*;
let range = self.inner.range(
Key::Symbol {
scope,
name,
kind: __First,
}..=Key::Symbol {
scope,
name,
kind: __TypeScope,
},
);
if let Some((&key, &Payload::Ast(index))) = range.rev().next() {
Some((key, index))
} else {
if let Some(&Payload::Ast(parent)) = self.inner.get(&Key::parent(scope)) {
self.find_type_symbol(parent, name, loc)
} else {
None
}
}
}
pub fn insert_symbol(&mut self, scope: Index, name: Intern<str>, kind: SymbolKind, ast: Index) {
self.inner
.insert(Key::Symbol { scope, name, kind }, Payload::Ast(ast));
}
}