placeness, constants
This commit is contained in:
parent
f67bb61888
commit
b0b87c68f2
|
|
@ -11,7 +11,7 @@ use chumsky::{
|
|||
select, text,
|
||||
};
|
||||
use internment::Intern;
|
||||
use lexer::{Token, TokenItemIterator, TokenIterator};
|
||||
use lexer::{Radix, Token, TokenItemIterator, TokenIterator};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
|
@ -111,6 +111,15 @@ pub enum ControlFlowKind {
|
|||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct Index(u32);
|
||||
|
||||
impl Index {
|
||||
pub fn as_value(self) -> PlaceOrValue {
|
||||
PlaceOrValue::Value(self)
|
||||
}
|
||||
pub fn as_place(self) -> PlaceOrValue {
|
||||
PlaceOrValue::Place(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AstNode {
|
||||
Root {
|
||||
|
|
@ -303,6 +312,21 @@ pub enum AstNode {
|
|||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum PlaceOrValue {
|
||||
Place(Index),
|
||||
Value(Index),
|
||||
}
|
||||
|
||||
impl PlaceOrValue {
|
||||
pub fn index(self) -> Index {
|
||||
match self {
|
||||
PlaceOrValue::Place(i) => i,
|
||||
PlaceOrValue::Value(i) => i,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
|
||||
pub enum Visibility {
|
||||
#[default]
|
||||
|
|
@ -448,7 +472,7 @@ fn visibility<'a>() -> impl Parser<'a, TokenInput<'a>, Visibility, ParserExtra>
|
|||
.map(|v| v.unwrap_or(Visibility::Private))
|
||||
}
|
||||
|
||||
fn func_parser() {
|
||||
fn func_parser<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> {
|
||||
let ident = select! {Token::Ident(ident) => ident};
|
||||
|
||||
let param = just(Token::Mutable)
|
||||
|
|
@ -473,7 +497,7 @@ fn func_parser() {
|
|||
.labelled("function parameters")
|
||||
.map(|params| ParameterList { parameters: params });
|
||||
|
||||
let func = visibility()
|
||||
visibility()
|
||||
.then_ignore(just(Token::Fn))
|
||||
.then(ident)
|
||||
.then(params)
|
||||
|
|
@ -491,22 +515,25 @@ fn func_parser() {
|
|||
visibility: vis,
|
||||
return_type: ret.unwrap_or_else(|| Intern::new(InnerType::Unit)),
|
||||
parameter_list: params,
|
||||
body,
|
||||
body: body.index(),
|
||||
}))
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
type ParserExtra = chumsky::extra::Full<EmptyErr, SimpleState<Ast>, ()>;
|
||||
|
||||
fn block<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> + Clone {
|
||||
fn block<'a>() -> impl Parser<'a, TokenInput<'a>, PlaceOrValue, ParserExtra> + Clone {
|
||||
just(Token::OpenBrace)
|
||||
.ignored()
|
||||
.then_ignore(just(Token::CloseBrace))
|
||||
.map_with(|_, e: &mut MapExtra<'_, '_, _, ParserExtra>| {
|
||||
e.state().push(AstNode::Block {
|
||||
statements: vec![],
|
||||
expr: None,
|
||||
})
|
||||
e.state()
|
||||
.push(AstNode::Block {
|
||||
statements: vec![],
|
||||
expr: None,
|
||||
})
|
||||
.as_value()
|
||||
// TODO: add statements and expr and map placeness by expr
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -525,24 +552,47 @@ fn unit<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> + Clone {
|
|||
type E<'a, 'b> = MapExtra<'a, 'b, TokenInput<'a>, ParserExtra>;
|
||||
|
||||
fn simple_expr<'a, 'b>(
|
||||
expr: Recursive<Direct<'a, 'b, TokenInput<'a>, Index, ParserExtra>>,
|
||||
) -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> + Clone {
|
||||
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(),
|
||||
})
|
||||
e.state()
|
||||
.push(AstNode::UnresolvedDeclRef {
|
||||
name: ident.to_string(),
|
||||
})
|
||||
.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(),
|
||||
unit().map(PlaceOrValue::Value),
|
||||
ident,
|
||||
constant,
|
||||
expr.delimited_by(just(Token::OpenParens), just(Token::CloseParens)),
|
||||
block(),
|
||||
))
|
||||
}
|
||||
|
||||
fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> {
|
||||
fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, PlaceOrValue, ParserExtra> {
|
||||
let assignment = choice((
|
||||
just(Token::Equal),
|
||||
just(Token::PlusEqual),
|
||||
|
|
@ -587,17 +637,40 @@ fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> {
|
|||
|
||||
let r#as = just(Token::As).ignore_then(type_parser::<ParserExtra>());
|
||||
|
||||
// TODO: postfix: function call, field access, array subscript
|
||||
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()
|
||||
}
|
||||
|
||||
recursive(|_expr| {
|
||||
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
|
||||
recursive(move |_expr| {
|
||||
let simple = simple_expr(_expr.clone());
|
||||
|
||||
let subscript = _expr.clone().delimited_by(
|
||||
just(Token::OpenSquareBracket),
|
||||
just(Token::CloseSquareBracket),
|
||||
);
|
||||
let subscript = _expr
|
||||
.clone()
|
||||
.delimited_by(
|
||||
just(Token::OpenSquareBracket),
|
||||
just(Token::CloseSquareBracket),
|
||||
)
|
||||
// subscript takes a value as the index
|
||||
.map_with(into_value);
|
||||
|
||||
let arguments = _expr
|
||||
.clone()
|
||||
// arguments take values
|
||||
.map_with(into_value)
|
||||
.map(PlaceOrValue::index)
|
||||
.separated_by(just(Token::Comma))
|
||||
.allow_trailing()
|
||||
.collect::<Vec<_>>()
|
||||
|
|
@ -606,61 +679,88 @@ fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> {
|
|||
let field = just(Token::Dot).ignore_then(select! {Token::Ident(ident) => ident});
|
||||
|
||||
let assignment_expr = simple.pratt((
|
||||
postfix(100, subscript, |expr, index, e: &mut E| {
|
||||
let node = AstNode::Subscript { expr, index };
|
||||
e.state().push(node)
|
||||
postfix(100, subscript, |expr, index: PlaceOrValue, e: &mut E| {
|
||||
let node = AstNode::Subscript {
|
||||
expr: into_value(expr, e).index(),
|
||||
index: index.index(),
|
||||
};
|
||||
// subscript yields a place
|
||||
e.state().push(node).as_place()
|
||||
}),
|
||||
postfix(100, arguments, |callee, arguments, e: &mut E| {
|
||||
let node = AstNode::CallExpr { callee, arguments };
|
||||
e.state().push(node)
|
||||
let node = AstNode::CallExpr {
|
||||
callee: into_value(callee, e).index(),
|
||||
arguments,
|
||||
};
|
||||
// function call yields a value
|
||||
e.state().push(node).as_value()
|
||||
}),
|
||||
postfix(100, field, |expr, field: &str, e: &mut E| {
|
||||
let node = AstNode::FieldAccess {
|
||||
expr,
|
||||
expr: into_place(expr, e).index(),
|
||||
field: field.to_string(),
|
||||
};
|
||||
e.state().push(node)
|
||||
// field access yields a place
|
||||
e.state().push(node).as_place()
|
||||
}),
|
||||
postfix(99, r#as, |expr, ty, e: &mut E| {
|
||||
let node = AstNode::ExplicitCast { expr, ty };
|
||||
e.state().push(node)
|
||||
let node = AstNode::ExplicitCast {
|
||||
expr: into_value(expr, e).index(),
|
||||
ty,
|
||||
};
|
||||
e.state().push(node).as_value()
|
||||
}),
|
||||
prefix(95, prefixes, |op, expr, e: &mut E| {
|
||||
let node = match op {
|
||||
Token::Bang => AstNode::Not(expr),
|
||||
Token::Minus => AstNode::Negate(expr),
|
||||
Token::Star => AstNode::Deref { expr },
|
||||
Token::Ampersand => AstNode::AddressOf { expr },
|
||||
Token::Bang => AstNode::Not(into_value(expr, e).index()),
|
||||
Token::Minus => AstNode::Negate(into_value(expr, e).index()),
|
||||
Token::Star => {
|
||||
return e
|
||||
.state()
|
||||
.push(AstNode::Deref { expr: expr.index() })
|
||||
.as_place();
|
||||
}
|
||||
Token::Ampersand => AstNode::AddressOf {
|
||||
expr: into_place(expr, e).index(),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
e.state().push(node)
|
||||
e.state().push(node).as_value()
|
||||
}),
|
||||
infix(left(90), multiplicative, |left, op, right, e: &mut E| {
|
||||
let left = into_value(left, e).index();
|
||||
let right = into_value(right, e).index();
|
||||
let node = match op {
|
||||
Token::Star => AstNode::Multiply { left, right },
|
||||
Token::Slash => AstNode::Divide { left, right },
|
||||
Token::Percent => AstNode::Modulus { left, right },
|
||||
_ => unreachable!(),
|
||||
};
|
||||
e.state().push(node)
|
||||
e.state().push(node).as_value()
|
||||
}),
|
||||
infix(left(80), additive, |left, op, right, e: &mut E| {
|
||||
let left = into_value(left, e).index();
|
||||
let right = into_value(right, e).index();
|
||||
let node = match op {
|
||||
Token::Plus => AstNode::Add { left, right },
|
||||
Token::Minus => AstNode::Subtract { left, right },
|
||||
_ => unreachable!(),
|
||||
};
|
||||
e.state().push(node)
|
||||
e.state().push(node).as_value()
|
||||
}),
|
||||
infix(left(70), shift, |left, op, right, e: &mut E| {
|
||||
let left = into_value(left, e).index();
|
||||
let right = into_value(right, e).index();
|
||||
let node = match op {
|
||||
Token::LessLess => AstNode::ShiftLeft { left, right },
|
||||
Token::GreaterGreater => AstNode::ShiftRight { left, right },
|
||||
_ => unreachable!(),
|
||||
};
|
||||
e.state().push(node)
|
||||
e.state().push(node).as_value()
|
||||
}),
|
||||
infix(left(60), relational, |left, op, right, e: &mut E| {
|
||||
let left = into_value(left, e).index();
|
||||
let right = into_value(right, e).index();
|
||||
let node = match op {
|
||||
Token::Less => AstNode::Less { left, right },
|
||||
Token::LessEqual => AstNode::LessEq { left, right },
|
||||
|
|
@ -668,64 +768,73 @@ fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> {
|
|||
Token::GreaterEqual => AstNode::GreaterEq { left, right },
|
||||
_ => unreachable!(),
|
||||
};
|
||||
e.state().push(node)
|
||||
e.state().push(node).as_value()
|
||||
}),
|
||||
infix(left(50), equality, |left, op, right, e: &mut E| {
|
||||
let left = into_value(left, e).index();
|
||||
let right = into_value(right, e).index();
|
||||
let node = match op {
|
||||
Token::EqualEqual => AstNode::Eq { left, right },
|
||||
Token::BangEqual => AstNode::NotEq { left, right },
|
||||
_ => unreachable!(),
|
||||
};
|
||||
e.state().push(node)
|
||||
e.state().push(node).as_value()
|
||||
}),
|
||||
infix(left(40), and, |left, _op, right, e: &mut E| {
|
||||
let left = into_value(left, e).index();
|
||||
let right = into_value(right, e).index();
|
||||
let node = AstNode::BitAnd { left, right };
|
||||
e.state().push(node)
|
||||
e.state().push(node).as_value()
|
||||
}),
|
||||
infix(left(30), xor, |left, _op, right, e: &mut E| {
|
||||
let left = into_value(left, e).index();
|
||||
let right = into_value(right, e).index();
|
||||
let node = AstNode::BitXor { left, right };
|
||||
e.state().push(node)
|
||||
e.state().push(node).as_value()
|
||||
}),
|
||||
infix(left(20), or, |left, _op, right, e: &mut E| {
|
||||
let left = into_value(left, e).index();
|
||||
let right = into_value(right, e).index();
|
||||
let node = AstNode::BitOr { left, right };
|
||||
e.state().push(node)
|
||||
e.state().push(node).as_value()
|
||||
}),
|
||||
infix(left(10), logical_and, |left, _op, right, e: &mut E| {
|
||||
let left = into_value(left, e).index();
|
||||
let right = into_value(right, e).index();
|
||||
let node = AstNode::LogicalAnd { left, right };
|
||||
e.state().push(node)
|
||||
e.state().push(node).as_value()
|
||||
}),
|
||||
infix(left(5), logical_or, |left, _op, right, e: &mut E| {
|
||||
let left = into_value(left, e).index();
|
||||
let right = into_value(right, e).index();
|
||||
let node = AstNode::LogicalOr { left, right };
|
||||
e.state().push(node)
|
||||
e.state().push(node).as_value()
|
||||
}),
|
||||
infix(right(1), assignment, |left, op, right, e: &mut E| {
|
||||
let left = match op {
|
||||
Token::Equal => {
|
||||
let node = AstNode::Assignment {
|
||||
dest: left,
|
||||
expr: right,
|
||||
};
|
||||
return e.state().push(node);
|
||||
}
|
||||
Token::PlusEqual => e.state().push(AstNode::Add { left, right }),
|
||||
Token::MinusEqual => e.state().push(AstNode::Subtract { left, right }),
|
||||
Token::StarEqual => e.state().push(AstNode::Multiply { left, right }),
|
||||
Token::SlashEqual => e.state().push(AstNode::Divide { left, right }),
|
||||
Token::PercentEqual => e.state().push(AstNode::Modulus { left, right }),
|
||||
Token::AmpersandEqual => e.state().push(AstNode::BitAnd { left, right }),
|
||||
Token::PipeEqual => e.state().push(AstNode::BitOr { left, right }),
|
||||
Token::CaretEqual => e.state().push(AstNode::BitXor { left, right }),
|
||||
Token::LessLessEqual => e.state().push(AstNode::ShiftLeft { left, right }),
|
||||
Token::GreaterGreaterEqual => {
|
||||
e.state().push(AstNode::ShiftRight { left, right })
|
||||
}
|
||||
_ => unreachable!(),
|
||||
let dest = into_place(left, e).index();
|
||||
let right = into_value(right, e).index();
|
||||
let node = if op == Token::Equal {
|
||||
AstNode::Assignment { dest, expr: right }
|
||||
} else {
|
||||
let left = into_value(left, e).index();
|
||||
let right = match op {
|
||||
Token::PlusEqual => e.state().push(AstNode::Add { left, right }),
|
||||
Token::MinusEqual => e.state().push(AstNode::Subtract { left, right }),
|
||||
Token::StarEqual => e.state().push(AstNode::Multiply { left, right }),
|
||||
Token::SlashEqual => e.state().push(AstNode::Divide { left, right }),
|
||||
Token::PercentEqual => e.state().push(AstNode::Modulus { left, right }),
|
||||
Token::AmpersandEqual => e.state().push(AstNode::BitAnd { left, right }),
|
||||
Token::PipeEqual => e.state().push(AstNode::BitOr { left, right }),
|
||||
Token::CaretEqual => e.state().push(AstNode::BitXor { left, right }),
|
||||
Token::LessLessEqual => e.state().push(AstNode::ShiftLeft { left, right }),
|
||||
Token::GreaterGreaterEqual => {
|
||||
e.state().push(AstNode::ShiftRight { left, right })
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
AstNode::Assignment { dest, expr: right }
|
||||
};
|
||||
let node = AstNode::Assignment {
|
||||
dest: left,
|
||||
expr: right,
|
||||
};
|
||||
e.state().push(node)
|
||||
e.state().push(node).as_value()
|
||||
}),
|
||||
));
|
||||
|
||||
|
|
@ -735,17 +844,20 @@ fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> {
|
|||
.ignore_then(
|
||||
_expr
|
||||
.clone()
|
||||
.map_with(into_value)
|
||||
.map(PlaceOrValue::index)
|
||||
.delimited_by(just(Token::OpenParens), just(Token::CloseParens)),
|
||||
)
|
||||
.then(_expr.clone())
|
||||
.then(else_expr.or_not())
|
||||
.map_with(|((condition, then), r#else), e: &mut E| {
|
||||
.map_with(|((condition, then), or), e: &mut E| {
|
||||
// TODO: determine placeness from branches
|
||||
let node = AstNode::If {
|
||||
condition,
|
||||
then,
|
||||
r#else,
|
||||
then: then.index(),
|
||||
r#else: or.map(PlaceOrValue::index),
|
||||
};
|
||||
e.state().push(node)
|
||||
e.state().push(node).as_value()
|
||||
});
|
||||
|
||||
let expr = choice((if_expr, assignment_expr)).labelled("expression");
|
||||
|
|
@ -830,5 +942,6 @@ mod tests {
|
|||
|
||||
print_ast(new_token_input("()"));
|
||||
print_ast(new_token_input("!() as i32"));
|
||||
print_ast(new_token_input("1 << 2 & 3"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue