1
0

Implement enum definition parsing

This commit is contained in:
Jeff 2024-03-18 11:23:44 -04:00
parent b7ae0f1b52
commit 77ded361ff
7 changed files with 143 additions and 22 deletions

View File

@ -0,0 +1,45 @@
use super::{AbstractTree, Identifier, Type, WithPosition};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct EnumDefinition {
name: Identifier,
type_parameters: Vec<Identifier>,
variants: Vec<(Identifier, Vec<WithPosition<Type>>)>,
}
impl EnumDefinition {
pub fn new(
name: Identifier,
type_parameters: Vec<Identifier>,
variants: Vec<(Identifier, Vec<WithPosition<Type>>)>,
) -> Self {
Self {
name,
type_parameters,
variants,
}
}
}
impl AbstractTree for EnumDefinition {
fn expected_type(
&self,
_context: &crate::context::Context,
) -> Result<Type, crate::error::ValidationError> {
todo!()
}
fn validate(
&self,
_context: &crate::context::Context,
) -> Result<(), crate::error::ValidationError> {
todo!()
}
fn run(
self,
_context: &crate::context::Context,
) -> Result<super::Action, crate::error::RuntimeError> {
todo!()
}
}

View File

@ -1,5 +1,6 @@
pub mod assignment;
pub mod block;
pub mod enum_definition;
pub mod expression;
pub mod function_call;
pub mod identifier;
@ -19,6 +20,7 @@ use chumsky::span::{SimpleSpan, Span};
pub use self::{
assignment::{Assignment, AssignmentOperator},
block::Block,
enum_definition::EnumDefinition,
expression::Expression,
function_call::FunctionCall,
identifier::Identifier,

View File

@ -3,13 +3,16 @@ use crate::{
error::{RuntimeError, ValidationError},
};
use super::{AbstractTree, Action, Assignment, Block, Expression, IfElse, Loop, Type, While};
use super::{
AbstractTree, Action, Assignment, Block, EnumDefinition, Expression, IfElse, Loop, Type, While,
};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Statement {
Assignment(Assignment),
Block(Block),
Break,
EnumDefinition(EnumDefinition),
Expression(Expression),
IfElse(IfElse),
Loop(Loop),
@ -22,6 +25,7 @@ impl AbstractTree for Statement {
Statement::Assignment(assignment) => assignment.expected_type(_context),
Statement::Block(block) => block.expected_type(_context),
Statement::Break => Ok(Type::None),
Statement::EnumDefinition(_) => todo!(),
Statement::Expression(expression) => expression.expected_type(_context),
Statement::IfElse(if_else) => if_else.expected_type(_context),
Statement::Loop(r#loop) => r#loop.expected_type(_context),
@ -34,6 +38,7 @@ impl AbstractTree for Statement {
Statement::Assignment(assignment) => assignment.validate(_context),
Statement::Block(block) => block.validate(_context),
Statement::Break => Ok(()),
Statement::EnumDefinition(_) => todo!(),
Statement::Expression(expression) => expression.validate(_context),
Statement::IfElse(if_else) => if_else.validate(_context),
Statement::Loop(r#loop) => r#loop.validate(_context),
@ -46,6 +51,7 @@ impl AbstractTree for Statement {
Statement::Assignment(assignment) => assignment.run(_context),
Statement::Block(block) => block.run(_context),
Statement::Break => Ok(Action::Break),
Statement::EnumDefinition(_) => todo!(),
Statement::Expression(expression) => expression.run(_context),
Statement::IfElse(if_else) => if_else.run(_context),
Statement::Loop(r#loop) => r#loop.run(_context),

View File

@ -1,6 +1,6 @@
use std::fmt::{self, Display, Formatter};
use chumsky::{prelude::*, text::whitespace};
use chumsky::prelude::*;
use crate::error::Error;
@ -217,6 +217,7 @@ pub fn lexer<'src>() -> impl Parser<
just("bool").padded(),
just("break").padded(),
just("else").padded(),
just("enum").padded(),
just("float").padded(),
just("int").padded(),
just("if").padded(),
@ -228,11 +229,10 @@ pub fn lexer<'src>() -> impl Parser<
just("loop").padded(),
just("while").padded(),
))
.delimited_by(whitespace(), whitespace())
.map(Token::Keyword);
choice((
boolean, float, integer, string, identifier, keyword, control, operator,
boolean, float, integer, string, keyword, identifier, control, operator,
))
.map_with(|token, state| (token, state.span()))
.padded()
@ -270,7 +270,7 @@ mod tests {
#[test]
fn keywords() {
assert_eq!(lex("int").unwrap()[0].0, Token::Keyword("int"))
assert_eq!(lex("int ").unwrap()[0].0, Token::Keyword("int"))
}
#[test]

View File

@ -424,7 +424,48 @@ pub fn parser<'src>() -> DustParser<'src> {
.with_position(state.span())
});
let enum_variant = identifier.clone().then(
r#type
.clone()
.separated_by(just(Token::Control(Control::Comma)))
.allow_trailing()
.collect()
.delimited_by(
just(Token::Control(Control::ParenOpen)),
just(Token::Control(Control::ParenClose)),
),
);
let enum_definition = just(Token::Keyword("enum"))
.ignore_then(identifier.clone())
.then(
identifier
.clone()
.separated_by(just(Token::Control(Control::Comma)))
.allow_trailing()
.collect()
.delimited_by(
just(Token::Control(Control::ParenOpen)),
just(Token::Control(Control::ParenClose)),
),
)
.then(
enum_variant
.separated_by(just(Token::Control(Control::Comma)))
.allow_trailing()
.collect()
.delimited_by(
just(Token::Control(Control::CurlyOpen)),
just(Token::Control(Control::CurlyClose)),
),
)
.map_with(|((name, type_parameters), variants), state| {
Statement::EnumDefinition(EnumDefinition::new(name, type_parameters, variants))
.with_position(state.span())
});
choice((
enum_definition,
if_else,
assignment,
expression_statement,
@ -445,6 +486,37 @@ mod tests {
use super::*;
#[test]
fn enum_definition() {
assert_eq!(
parse(
&lex("
enum FooBar (F, B) {
Foo(F),
Bar(B),
}
")
.unwrap()
)
.unwrap()[0]
.node,
Statement::EnumDefinition(EnumDefinition::new(
Identifier::new("FooBar"),
vec![Identifier::new("F"), Identifier::new("B")],
vec![
(
Identifier::new("Foo"),
vec![Type::Custom(Identifier::new("F")).with_position((0, 0))],
),
(
Identifier::new("Bar"),
vec![Type::Custom(Identifier::new("B")).with_position((0, 0))]
)
]
))
);
}
#[test]
fn map_index() {
assert_eq!(

View File

@ -3,7 +3,6 @@ use std::{
collections::BTreeMap,
fmt::{self, Display, Formatter},
io::stdin,
num::ParseIntError,
ops::Range,
sync::{Arc, OnceLock},
};
@ -18,7 +17,7 @@ use stanza::{
use crate::{
abstract_tree::{AbstractTree, Action, Block, Identifier, Type, WithPosition},
context::Context,
error::{RuntimeError, ValidationError},
error::RuntimeError,
};
#[derive(Clone, Debug, PartialEq)]
@ -354,18 +353,15 @@ impl BuiltInFunction {
let string = arguments.get(0).unwrap();
if let ValueInner::String(string) = string.inner().as_ref() {
// let integer = string.parse();
let integer = if let Ok(integer) = string.parse() {
integer
} else {
todo!()
};
todo!()
// Ok(Action::Return(Value::integer(integer)))
Ok(Action::Return(Value::integer(integer)))
} else {
Err(RuntimeError::ValidationFailure(
ValidationError::WrongArguments {
expected: vec![Type::String],
actual: arguments.iter().map(|value| value.r#type()).collect(),
},
))
todo!()
}
}
BuiltInFunction::IntRandomRange => {
@ -409,24 +405,24 @@ impl Display for BuiltInFunction {
static INT: OnceLock<Value> = OnceLock::new();
static IO: OnceLock<Value> = OnceLock::new();
pub const BUILT_IN_MODULES: [BuiltInModule; 2] = [BuiltInModule::Integer, BuiltInModule::Io];
pub const BUILT_IN_MODULES: [BuiltInModule; 2] = [BuiltInModule::Int, BuiltInModule::Io];
pub enum BuiltInModule {
Integer,
Int,
Io,
}
impl BuiltInModule {
pub fn name(&self) -> &'static str {
match self {
BuiltInModule::Integer => "int",
BuiltInModule::Int => "int",
BuiltInModule::Io => "io",
}
}
pub fn value(self) -> Value {
match self {
BuiltInModule::Integer => {
BuiltInModule::Int => {
let mut properties = BTreeMap::new();
properties.insert(

View File

@ -47,7 +47,7 @@ fn callback() {
#[test]
fn built_in_function_call() {
assert_eq!(interpret("output('Hiya')"), Ok(None));
assert_eq!(interpret("io.write_line('Hiya')"), Ok(None));
}
#[test]