Compare commits
No commits in common. "51ef019fd192f462a345af13247326a334096ec8" and "b0b87c68f26a81d370c804daa4552d50792ae88b" have entirely different histories.
51ef019fd1
...
b0b87c68f2
|
|
@ -380,14 +380,21 @@ 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.take_while_inclusive(|&c| c != '\n').for_each(drop);
|
source
|
||||||
|
.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| is_things::is_whitespace(c) && c != '\n')
|
.take_while_ref(|&c| {
|
||||||
|
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('/')) {
|
||||||
|
|
|
||||||
|
|
@ -496,6 +496,8 @@ 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 {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{fmt::Display, hash::Hash, ops::Range, sync::Arc};
|
use std::{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, none_of, recursive, via_parser},
|
prelude::{Recursive, choice, just, recursive},
|
||||||
recursive::{Direct, Indirect},
|
recursive::Direct,
|
||||||
select, text,
|
select, text,
|
||||||
};
|
};
|
||||||
use internment::Intern;
|
use internment::Intern;
|
||||||
|
|
@ -63,86 +63,6 @@ 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,
|
||||||
|
|
@ -188,18 +108,8 @@ pub enum ControlFlowKind {
|
||||||
Continue,
|
Continue,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ControlFlowKind {
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
fn as_str(&self) -> &'static str {
|
pub struct Index(u32);
|
||||||
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 {
|
||||||
|
|
@ -218,7 +128,14 @@ pub enum AstNode {
|
||||||
File {
|
File {
|
||||||
decls: Vec<Index>,
|
decls: Vec<Index>,
|
||||||
},
|
},
|
||||||
ParameterList(ParameterList),
|
FunctionProto {
|
||||||
|
name: String,
|
||||||
|
return_type: Type,
|
||||||
|
parameter_list: Index,
|
||||||
|
},
|
||||||
|
ParameterList {
|
||||||
|
parameters: Vec<Index>,
|
||||||
|
},
|
||||||
Parameter(Parameter),
|
Parameter(Parameter),
|
||||||
FunctionDecl(FunctionDecl),
|
FunctionDecl(FunctionDecl),
|
||||||
Block {
|
Block {
|
||||||
|
|
@ -240,7 +157,7 @@ pub enum AstNode {
|
||||||
VarDecl {
|
VarDecl {
|
||||||
mutable: bool,
|
mutable: bool,
|
||||||
name: String,
|
name: String,
|
||||||
var_type: Option<Type>,
|
var_type: Type,
|
||||||
},
|
},
|
||||||
Assignment {
|
Assignment {
|
||||||
dest: Index,
|
dest: Index,
|
||||||
|
|
@ -249,7 +166,7 @@ pub enum AstNode {
|
||||||
GlobalDecl {
|
GlobalDecl {
|
||||||
name: String,
|
name: String,
|
||||||
var_type: Type,
|
var_type: Type,
|
||||||
expr: Index,
|
value: Index,
|
||||||
},
|
},
|
||||||
StructDecl {
|
StructDecl {
|
||||||
name: String,
|
name: String,
|
||||||
|
|
@ -408,20 +325,6 @@ 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)]
|
||||||
|
|
@ -432,9 +335,13 @@ pub enum Visibility {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum ParseError {
|
pub enum ParseError<'a> {
|
||||||
#[error("expected a valid if condition expression")]
|
#[error("End of file.")]
|
||||||
IfCondition,
|
EOF,
|
||||||
|
#[error("Unexpected token: {0:?}")]
|
||||||
|
UnexpectedToken(Token<'a>),
|
||||||
|
#[error("Not a type.")]
|
||||||
|
NotAType,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
|
|
@ -442,14 +349,6 @@ 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()
|
||||||
|
|
@ -467,7 +366,7 @@ pub struct FunctionDecl {
|
||||||
name: String,
|
name: String,
|
||||||
visibility: Visibility,
|
visibility: Visibility,
|
||||||
return_type: Type,
|
return_type: Type,
|
||||||
parameter_list: Index,
|
parameter_list: ParameterList,
|
||||||
body: Index,
|
body: Index,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -514,7 +413,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> + Clone
|
fn type_parser<'a, E>() -> impl Parser<'a, TokenInput<'a>, Type, E>
|
||||||
where
|
where
|
||||||
E: chumsky::extra::ParserExtra<'a, TokenInput<'a>, Error = EmptyErr> + 'a,
|
E: chumsky::extra::ParserExtra<'a, TokenInput<'a>, Error = EmptyErr> + 'a,
|
||||||
{
|
{
|
||||||
|
|
@ -567,153 +466,17 @@ where
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visibility<'a>() -> impl Parser<'a, TokenInput<'a>, Visibility, ParserExtra> + Clone {
|
fn visibility<'a>() -> impl Parser<'a, TokenInput<'a>, Visibility, ParserExtra> {
|
||||||
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))
|
||||||
}
|
}
|
||||||
|
|
||||||
type ParserExtra = chumsky::extra::Full<EmptyErr, SimpleState<Ast>, ()>;
|
fn func_parser<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> {
|
||||||
|
|
||||||
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 = select! {Token::Mutable => ()}
|
let param = just(Token::Mutable)
|
||||||
|
.to(())
|
||||||
.or_not()
|
.or_not()
|
||||||
.then(ident)
|
.then(ident)
|
||||||
.then_ignore(just(Token::Colon))
|
.then_ignore(just(Token::Colon))
|
||||||
|
|
@ -732,26 +495,22 @@ where
|
||||||
.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_with(|params, e: &mut E| {
|
.map(|params| ParameterList { parameters: params });
|
||||||
e.state()
|
|
||||||
.push(AstNode::ParameterList(ParameterList { parameters: params }))
|
|
||||||
});
|
|
||||||
|
|
||||||
let ret_type = just(Token::MinusGreater)
|
visibility()
|
||||||
.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)
|
||||||
.then(ret_type)
|
// optional return type
|
||||||
.then(self.block())
|
.then(
|
||||||
.map_with(|(((((attrs, vis), ident), params), ret), body), e| {
|
just(Token::MinusGreater)
|
||||||
|
.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,
|
attrs: None,
|
||||||
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)),
|
||||||
|
|
@ -761,44 +520,79 @@ where
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block(
|
type ParserExtra = chumsky::extra::Full<EmptyErr, SimpleState<Ast>, ()>;
|
||||||
&self,
|
|
||||||
) -> impl Parser<'src, TokenInput<'src>, PlaceOrValue, ParserExtra> + Clone + use<'src, 'b>
|
fn block<'a>() -> impl Parser<'a, TokenInput<'a>, PlaceOrValue, ParserExtra> + Clone {
|
||||||
{
|
just(Token::OpenBrace)
|
||||||
self.stmt()
|
.ignored()
|
||||||
.repeated()
|
.then_ignore(just(Token::CloseBrace))
|
||||||
.collect::<Vec<_>>()
|
.map_with(|_, e: &mut MapExtra<'_, '_, _, ParserExtra>| {
|
||||||
.then(self.expr.clone().or_not())
|
e.state()
|
||||||
.delimited_by(just(Token::OpenBrace), just(Token::CloseBrace))
|
.push(AstNode::Block {
|
||||||
.map_with(|(statements, expr), e: &mut E| {
|
statements: vec![],
|
||||||
expr.unwrap_or(PlaceOrValue::Value(Index(u32::MAX)))
|
expr: None,
|
||||||
.with_index(e.state().push(AstNode::Block {
|
})
|
||||||
statements,
|
.as_value()
|
||||||
expr: expr.map(PlaceOrValue::index),
|
// TODO: add statements and expr and map placeness by expr
|
||||||
}))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_value(idx: PlaceOrValue, e: &mut E) -> PlaceOrValue {
|
fn unit<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> + Clone {
|
||||||
match idx {
|
just(Token::OpenParens)
|
||||||
PlaceOrValue::Place(index) => e.state().push(AstNode::PlaceToValue { expr: index }),
|
.ignored()
|
||||||
PlaceOrValue::Value(index) => index,
|
.ignore_then(just(Token::CloseParens))
|
||||||
}
|
.map_with(|_, e: &mut MapExtra<TokenInput<'a>, ParserExtra>| {
|
||||||
.as_value()
|
e.state().push(AstNode::Constant {
|
||||||
|
ty: Intern::new(InnerType::Unit),
|
||||||
|
value: Intern::new(Value::Unit),
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_place(idx: PlaceOrValue, e: &mut E) -> PlaceOrValue {
|
type E<'a, 'b> = MapExtra<'a, 'b, TokenInput<'a>, ParserExtra>;
|
||||||
match idx {
|
|
||||||
PlaceOrValue::Value(index) => e.state().push(AstNode::ValueToPlace { expr: index }),
|
fn simple_expr<'a, 'b>(
|
||||||
PlaceOrValue::Place(index) => index,
|
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 create_expr(
|
fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, PlaceOrValue, ParserExtra> {
|
||||||
&'_ 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),
|
||||||
|
|
@ -843,8 +637,25 @@ where
|
||||||
|
|
||||||
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
|
||||||
let _expr = self.expr.clone();
|
recursive(move |_expr| {
|
||||||
|
let simple = simple_expr(_expr.clone());
|
||||||
|
|
||||||
let subscript = _expr
|
let subscript = _expr
|
||||||
.clone()
|
.clone()
|
||||||
|
|
@ -853,12 +664,12 @@ where
|
||||||
just(Token::CloseSquareBracket),
|
just(Token::CloseSquareBracket),
|
||||||
)
|
)
|
||||||
// subscript takes a value as the index
|
// subscript takes a value as the index
|
||||||
.map_with(Self::into_value);
|
.map_with(into_value);
|
||||||
|
|
||||||
let arguments = _expr
|
let arguments = _expr
|
||||||
.clone()
|
.clone()
|
||||||
// arguments take values
|
// arguments take values
|
||||||
.map_with(Self::into_value)
|
.map_with(into_value)
|
||||||
.map(PlaceOrValue::index)
|
.map(PlaceOrValue::index)
|
||||||
.separated_by(just(Token::Comma))
|
.separated_by(just(Token::Comma))
|
||||||
.allow_trailing()
|
.allow_trailing()
|
||||||
|
|
@ -867,10 +678,10 @@ where
|
||||||
|
|
||||||
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 = self.simple_expr().pratt((
|
let assignment_expr = simple.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: Self::into_value(expr, e).index(),
|
expr: into_value(expr, e).index(),
|
||||||
index: index.index(),
|
index: index.index(),
|
||||||
};
|
};
|
||||||
// subscript yields a place
|
// subscript yields a place
|
||||||
|
|
@ -878,7 +689,7 @@ where
|
||||||
}),
|
}),
|
||||||
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: Self::into_value(callee, e).index(),
|
callee: into_value(callee, e).index(),
|
||||||
arguments,
|
arguments,
|
||||||
};
|
};
|
||||||
// function call yields a value
|
// function call yields a value
|
||||||
|
|
@ -886,7 +697,7 @@ where
|
||||||
}),
|
}),
|
||||||
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: Self::into_place(expr, e).index(),
|
expr: into_place(expr, e).index(),
|
||||||
field: field.to_string(),
|
field: field.to_string(),
|
||||||
};
|
};
|
||||||
// field access yields a place
|
// field access yields a place
|
||||||
|
|
@ -894,15 +705,15 @@ where
|
||||||
}),
|
}),
|
||||||
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: Self::into_value(expr, e).index(),
|
expr: 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(Self::into_value(expr, e).index()),
|
Token::Bang => AstNode::Not(into_value(expr, e).index()),
|
||||||
Token::Minus => AstNode::Negate(Self::into_value(expr, e).index()),
|
Token::Minus => AstNode::Negate(into_value(expr, e).index()),
|
||||||
Token::Star => {
|
Token::Star => {
|
||||||
return e
|
return e
|
||||||
.state()
|
.state()
|
||||||
|
|
@ -910,15 +721,15 @@ where
|
||||||
.as_place();
|
.as_place();
|
||||||
}
|
}
|
||||||
Token::Ampersand => AstNode::AddressOf {
|
Token::Ampersand => AstNode::AddressOf {
|
||||||
expr: Self::into_place(expr, e).index(),
|
expr: 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 = Self::into_value(left, e).index();
|
let left = into_value(left, e).index();
|
||||||
let right = Self::into_value(right, e).index();
|
let right = 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 },
|
||||||
|
|
@ -928,8 +739,8 @@ where
|
||||||
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 = Self::into_value(left, e).index();
|
let left = into_value(left, e).index();
|
||||||
let right = Self::into_value(right, e).index();
|
let right = 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 },
|
||||||
|
|
@ -938,8 +749,8 @@ where
|
||||||
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 = Self::into_value(left, e).index();
|
let left = into_value(left, e).index();
|
||||||
let right = Self::into_value(right, e).index();
|
let right = 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 },
|
||||||
|
|
@ -948,8 +759,8 @@ where
|
||||||
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 = Self::into_value(left, e).index();
|
let left = into_value(left, e).index();
|
||||||
let right = Self::into_value(right, e).index();
|
let right = 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 },
|
||||||
|
|
@ -960,8 +771,8 @@ where
|
||||||
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 = Self::into_value(left, e).index();
|
let left = into_value(left, e).index();
|
||||||
let right = Self::into_value(right, e).index();
|
let right = 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 },
|
||||||
|
|
@ -970,42 +781,42 @@ where
|
||||||
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 = Self::into_value(left, e).index();
|
let left = into_value(left, e).index();
|
||||||
let right = Self::into_value(right, e).index();
|
let right = 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 = Self::into_value(left, e).index();
|
let left = into_value(left, e).index();
|
||||||
let right = Self::into_value(right, e).index();
|
let right = 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 = Self::into_value(left, e).index();
|
let left = into_value(left, e).index();
|
||||||
let right = Self::into_value(right, e).index();
|
let right = 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 = Self::into_value(left, e).index();
|
let left = into_value(left, e).index();
|
||||||
let right = Self::into_value(right, e).index();
|
let right = 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 = Self::into_value(left, e).index();
|
let left = into_value(left, e).index();
|
||||||
let right = Self::into_value(right, e).index();
|
let right = 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 = Self::into_place(left, e).index();
|
let dest = into_place(left, e).index();
|
||||||
let right = Self::into_value(right, e).index();
|
let right = 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 = Self::into_value(left, e).index();
|
let left = 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 }),
|
||||||
|
|
@ -1027,128 +838,41 @@ where
|
||||||
}),
|
}),
|
||||||
));
|
));
|
||||||
|
|
||||||
let expr = choice((self.if_else_expr(), assignment_expr)).labelled("expression");
|
let else_expr = just(Token::Else).ignore_then(_expr.clone());
|
||||||
|
|
||||||
expr
|
let if_expr = just(Token::If)
|
||||||
}
|
|
||||||
|
|
||||||
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(
|
||||||
self.expr()
|
_expr
|
||||||
.map_with(Self::into_value)
|
.clone()
|
||||||
|
.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(self.expr())
|
.then(_expr.clone())
|
||||||
.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| {
|
||||||
use PlaceOrValue::*;
|
// TODO: determine placeness from branches
|
||||||
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),
|
||||||
};
|
};
|
||||||
then.with_index(e.state().push(node))
|
e.state().push(node).as_value()
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
let expr = choice((if_expr, assignment_expr)).labelled("expression");
|
||||||
.at_least(1)
|
|
||||||
.collect::<Vec<_>>()
|
Arc::new(expr)
|
||||||
.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::{ParseResult, Parser, extra::SimpleState};
|
use chumsky::{Parser, extra::SimpleState};
|
||||||
|
|
||||||
use crate::{Ast, AstNode, ParserCtx, ParserExtra, new_token_input, pretty, type_parser};
|
use crate::{Ast, AstNode, new_token_input, type_parser};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn print_ast_node_size() {
|
fn print_ast_node_size() {
|
||||||
|
|
@ -1208,91 +932,16 @@ 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 ctx = crate::ParserCtx::new();
|
let print_ast = |tokens| {
|
||||||
|
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("true"), ctx.expr());
|
print_ast(new_token_input("()"));
|
||||||
}
|
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(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,398 +0,0 @@
|
||||||
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",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,178 +0,0 @@
|
||||||
//! 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue