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

View File

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

View File

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

View File

@ -424,7 +424,48 @@ pub fn parser<'src>() -> DustParser<'src> {
.with_position(state.span()) .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(( choice((
enum_definition,
if_else, if_else,
assignment, assignment,
expression_statement, expression_statement,
@ -445,6 +486,37 @@ mod tests {
use super::*; 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] #[test]
fn map_index() { fn map_index() {
assert_eq!( assert_eq!(

View File

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

View File

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