Expand lexer and parser with more tests
This commit is contained in:
parent
9d5b7b6606
commit
e5aeaa67d8
@ -1,23 +1,37 @@
|
|||||||
use crate::{error::RuntimeError, value::Value, Context};
|
use crate::{
|
||||||
|
error::{RuntimeError, ValidationError},
|
||||||
|
value::Value,
|
||||||
|
Context,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{AbstractTree, Identifier, Statement};
|
use super::{AbstractTree, Identifier, Statement, Type};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct Assignment<'src> {
|
pub struct Assignment<'src> {
|
||||||
identifier: Identifier,
|
identifier: Identifier,
|
||||||
|
r#type: Option<Type>,
|
||||||
statement: Box<Statement<'src>>,
|
statement: Box<Statement<'src>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> Assignment<'src> {
|
impl<'src> Assignment<'src> {
|
||||||
pub fn new(identifier: Identifier, statement: Statement<'src>) -> Self {
|
pub fn new(identifier: Identifier, r#type: Option<Type>, statement: Statement<'src>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
identifier,
|
identifier,
|
||||||
|
r#type,
|
||||||
statement: Box::new(statement),
|
statement: Box::new(statement),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> AbstractTree for Assignment<'src> {
|
impl<'src> AbstractTree for Assignment<'src> {
|
||||||
|
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn run(self, _context: &Context) -> Result<Value, RuntimeError> {
|
fn run(self, _context: &Context) -> Result<Value, RuntimeError> {
|
||||||
todo!()
|
todo!()
|
||||||
// let value = self.statement.run(context)?;
|
// let value = self.statement.run(context)?;
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
use crate::{context::Context, error::RuntimeError, Value};
|
use crate::{
|
||||||
|
context::Context,
|
||||||
|
error::{RuntimeError, ValidationError},
|
||||||
|
Value,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{AbstractTree, Statement};
|
use super::{AbstractTree, Statement, Type};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct Block<'src> {
|
pub struct Block<'src> {
|
||||||
@ -14,6 +18,14 @@ impl<'src> Block<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> AbstractTree for Block<'src> {
|
impl<'src> AbstractTree for Block<'src> {
|
||||||
|
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn run(self, _: &Context) -> Result<Value, RuntimeError> {
|
fn run(self, _: &Context) -> Result<Value, RuntimeError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
use crate::{context::Context, error::RuntimeError, Value};
|
use crate::{
|
||||||
|
context::Context,
|
||||||
|
error::{RuntimeError, ValidationError},
|
||||||
|
Value,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{AbstractTree, Identifier, Logic, ValueNode};
|
use super::{AbstractTree, Identifier, Logic, Type, ValueNode};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub enum Expression<'src> {
|
pub enum Expression<'src> {
|
||||||
@ -10,6 +14,14 @@ pub enum Expression<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> AbstractTree for Expression<'src> {
|
impl<'src> AbstractTree for Expression<'src> {
|
||||||
|
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn run(self, context: &Context) -> Result<Value, RuntimeError> {
|
fn run(self, context: &Context) -> Result<Value, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Expression::Identifier(identifier) => identifier.run(context),
|
Expression::Identifier(identifier) => identifier.run(context),
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{context::Context, error::RuntimeError, Value};
|
use crate::{
|
||||||
|
context::Context,
|
||||||
|
error::{RuntimeError, ValidationError},
|
||||||
|
Value,
|
||||||
|
};
|
||||||
|
|
||||||
use super::AbstractTree;
|
use super::{AbstractTree, Type};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct Identifier(Arc<String>);
|
pub struct Identifier(Arc<String>);
|
||||||
@ -14,6 +18,14 @@ impl Identifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Identifier {
|
impl AbstractTree for Identifier {
|
||||||
|
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn run(self, _context: &Context) -> Result<Value, RuntimeError> {
|
fn run(self, _context: &Context) -> Result<Value, RuntimeError> {
|
||||||
todo!()
|
todo!()
|
||||||
// let value = context.get(&self)?.unwrap_or_else(Value::none).clone();
|
// let value = context.get(&self)?.unwrap_or_else(Value::none).clone();
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
use crate::{context::Context, error::RuntimeError, Value};
|
use crate::{
|
||||||
|
context::Context,
|
||||||
|
error::{RuntimeError, ValidationError},
|
||||||
|
Value,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{AbstractTree, Expression};
|
use super::{AbstractTree, Expression, Type};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub enum Logic<'src> {
|
pub enum Logic<'src> {
|
||||||
@ -16,6 +20,14 @@ pub enum Logic<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> AbstractTree for Logic<'src> {
|
impl<'src> AbstractTree for Logic<'src> {
|
||||||
|
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn run(self, _context: &Context) -> Result<Value, RuntimeError> {
|
fn run(self, _context: &Context) -> Result<Value, RuntimeError> {
|
||||||
let boolean = match self {
|
let boolean = match self {
|
||||||
Logic::Equal(left, right) => left.run(_context)? == right.run(_context)?,
|
Logic::Equal(left, right) => left.run(_context)? == right.run(_context)?,
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
use crate::{context::Context, error::RuntimeError, Value};
|
use crate::{
|
||||||
|
context::Context,
|
||||||
|
error::{RuntimeError, ValidationError},
|
||||||
|
Value,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{AbstractTree, Block};
|
use super::{AbstractTree, Block, Type};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct Loop<'src> {
|
pub struct Loop<'src> {
|
||||||
@ -8,6 +12,14 @@ pub struct Loop<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> AbstractTree for Loop<'src> {
|
impl<'src> AbstractTree for Loop<'src> {
|
||||||
|
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn run(self, _: &Context) -> Result<Value, RuntimeError> {
|
fn run(self, _: &Context) -> Result<Value, RuntimeError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
@ -5,15 +5,22 @@ pub mod identifier;
|
|||||||
pub mod logic;
|
pub mod logic;
|
||||||
pub mod r#loop;
|
pub mod r#loop;
|
||||||
pub mod statement;
|
pub mod statement;
|
||||||
|
pub mod r#type;
|
||||||
pub mod value_node;
|
pub mod value_node;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
assignment::Assignment, block::Block, expression::Expression, identifier::Identifier,
|
assignment::Assignment, block::Block, expression::Expression, identifier::Identifier,
|
||||||
logic::Logic, r#loop::Loop, statement::Statement, value_node::ValueNode,
|
logic::Logic, r#loop::Loop, r#type::Type, statement::Statement, value_node::ValueNode,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{context::Context, error::RuntimeError, Value};
|
use crate::{
|
||||||
|
context::Context,
|
||||||
|
error::{RuntimeError, ValidationError},
|
||||||
|
Value,
|
||||||
|
};
|
||||||
|
|
||||||
pub trait AbstractTree {
|
pub trait AbstractTree {
|
||||||
|
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError>;
|
||||||
|
fn validate(&self, context: &Context) -> Result<(), ValidationError>;
|
||||||
fn run(self, context: &Context) -> Result<Value, RuntimeError>;
|
fn run(self, context: &Context) -> Result<Value, RuntimeError>;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
use crate::{context::Context, error::RuntimeError};
|
use crate::{
|
||||||
|
context::Context,
|
||||||
|
error::{RuntimeError, ValidationError},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{AbstractTree, Assignment, Block, Expression, Loop, Value};
|
use super::{AbstractTree, Assignment, Block, Expression, Loop, Type, Value};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub enum Statement<'src> {
|
pub enum Statement<'src> {
|
||||||
@ -11,6 +14,14 @@ pub enum Statement<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> AbstractTree for Statement<'src> {
|
impl<'src> AbstractTree for Statement<'src> {
|
||||||
|
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn run(self, _context: &Context) -> Result<Value, RuntimeError> {
|
fn run(self, _context: &Context) -> Result<Value, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Statement::Assignment(assignment) => assignment.run(_context),
|
Statement::Assignment(assignment) => assignment.run(_context),
|
||||||
|
40
src/abstract_tree/type.rs
Normal file
40
src/abstract_tree/type.rs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
use crate::abstract_tree::Identifier;
|
||||||
|
|
||||||
|
use super::AbstractTree;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
|
pub enum Type {
|
||||||
|
Boolean,
|
||||||
|
Custom(Identifier),
|
||||||
|
Float,
|
||||||
|
Integer,
|
||||||
|
List,
|
||||||
|
ListOf(Box<Type>),
|
||||||
|
ListExact(Vec<Type>),
|
||||||
|
Map,
|
||||||
|
Range,
|
||||||
|
String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AbstractTree for Type {
|
||||||
|
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<crate::Value, crate::error::RuntimeError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,12 @@
|
|||||||
use std::{cmp::Ordering, collections::BTreeMap, ops::Range};
|
use std::{cmp::Ordering, collections::BTreeMap, ops::Range};
|
||||||
|
|
||||||
use crate::{context::Context, error::RuntimeError, Value};
|
use crate::{
|
||||||
|
context::Context,
|
||||||
|
error::{RuntimeError, ValidationError},
|
||||||
|
Value,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{AbstractTree, Expression, Identifier};
|
use super::{AbstractTree, Expression, Identifier, Type};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum ValueNode<'src> {
|
pub enum ValueNode<'src> {
|
||||||
@ -17,6 +21,25 @@ pub enum ValueNode<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> AbstractTree for ValueNode<'src> {
|
impl<'src> AbstractTree for ValueNode<'src> {
|
||||||
|
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
||||||
|
let r#type = match self {
|
||||||
|
ValueNode::Boolean(_) => Type::Boolean,
|
||||||
|
ValueNode::Float(_) => Type::Float,
|
||||||
|
ValueNode::Integer(_) => Type::Integer,
|
||||||
|
ValueNode::List(_) => Type::List,
|
||||||
|
ValueNode::Map(_) => Type::Map,
|
||||||
|
ValueNode::Range(_) => Type::Range,
|
||||||
|
ValueNode::String(_) => Type::String,
|
||||||
|
ValueNode::Enum(name, _) => Type::Custom(name.clone()),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(r#type)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn run(self, _context: &Context) -> Result<Value, RuntimeError> {
|
fn run(self, _context: &Context) -> Result<Value, RuntimeError> {
|
||||||
let value = match self {
|
let value = match self {
|
||||||
ValueNode::Boolean(boolean) => Value::boolean(boolean),
|
ValueNode::Boolean(boolean) => Value::boolean(boolean),
|
||||||
|
20
src/error.rs
20
src/error.rs
@ -32,7 +32,7 @@ impl<'src> From<RuntimeError> for Error<'src> {
|
|||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum RuntimeError {
|
pub enum RuntimeError {
|
||||||
RwLockPoison(RwLockPoisonError),
|
RwLockPoison(RwLockPoisonError),
|
||||||
ExpectedBoolean,
|
ValidationFailure(ValidationError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<RwLockPoisonError> for RuntimeError {
|
impl From<RwLockPoisonError> for RuntimeError {
|
||||||
@ -41,6 +41,24 @@ impl From<RwLockPoisonError> for RuntimeError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ValidationError> for RuntimeError {
|
||||||
|
fn from(error: ValidationError) -> Self {
|
||||||
|
RuntimeError::ValidationFailure(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum ValidationError {
|
||||||
|
RwLockPoison(RwLockPoisonError),
|
||||||
|
ExpectedBoolean,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<RwLockPoisonError> for ValidationError {
|
||||||
|
fn from(error: RwLockPoisonError) -> Self {
|
||||||
|
ValidationError::RwLockPoison(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct RwLockPoisonError;
|
pub struct RwLockPoisonError;
|
||||||
|
|
||||||
|
37
src/lexer.rs
37
src/lexer.rs
@ -1,3 +1,5 @@
|
|||||||
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
use chumsky::prelude::*;
|
use chumsky::prelude::*;
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
@ -11,6 +13,22 @@ pub enum Token<'src> {
|
|||||||
Identifier(&'src str),
|
Identifier(&'src str),
|
||||||
Operator(&'src str),
|
Operator(&'src str),
|
||||||
Control(&'src str),
|
Control(&'src str),
|
||||||
|
Keyword(&'src str),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'src> Display for Token<'src> {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Token::Boolean(boolean) => write!(f, "{boolean}"),
|
||||||
|
Token::Integer(integer) => write!(f, "{integer}"),
|
||||||
|
Token::Float(float) => write!(f, "{float}"),
|
||||||
|
Token::String(string) => write!(f, "{string}"),
|
||||||
|
Token::Identifier(string) => write!(f, "{string}"),
|
||||||
|
Token::Operator(string) => write!(f, "{string}"),
|
||||||
|
Token::Control(string) => write!(f, "{string}"),
|
||||||
|
Token::Keyword(string) => write!(f, "{string}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lex<'src>(source: &'src str) -> Result<Vec<(Token, SimpleSpan)>, Error<'src>> {
|
pub fn lex<'src>(source: &'src str) -> Result<Vec<(Token, SimpleSpan)>, Error<'src>> {
|
||||||
@ -93,11 +111,23 @@ pub fn lexer<'src>() -> impl Parser<
|
|||||||
just(",").padded(),
|
just(",").padded(),
|
||||||
just(";").padded(),
|
just(";").padded(),
|
||||||
just("::").padded(),
|
just("::").padded(),
|
||||||
|
just(":").padded(),
|
||||||
))
|
))
|
||||||
.map(Token::Control);
|
.map(Token::Control);
|
||||||
|
|
||||||
|
let keyword = choice((
|
||||||
|
just("bool").padded(),
|
||||||
|
just("float").padded(),
|
||||||
|
just("int").padded(),
|
||||||
|
just("list").padded(),
|
||||||
|
just("map").padded(),
|
||||||
|
just("range").padded(),
|
||||||
|
just("str").padded(),
|
||||||
|
))
|
||||||
|
.map(Token::Keyword);
|
||||||
|
|
||||||
choice((
|
choice((
|
||||||
boolean, float, integer, string, identifier, operator, control,
|
boolean, float, integer, string, keyword, identifier, operator, control,
|
||||||
))
|
))
|
||||||
.map_with(|token, state| (token, state.span()))
|
.map_with(|token, state| (token, state.span()))
|
||||||
.padded()
|
.padded()
|
||||||
@ -109,6 +139,11 @@ pub fn lexer<'src>() -> impl Parser<
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn keywords() {
|
||||||
|
assert_eq!(lex("int").unwrap()[0].0, Token::Keyword("int"))
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn identifier() {
|
fn identifier() {
|
||||||
assert_eq!(lex("x").unwrap()[0].0, Token::Identifier("x"));
|
assert_eq!(lex("x").unwrap()[0].0, Token::Identifier("x"));
|
||||||
|
@ -104,7 +104,7 @@ fn parser<'tokens, 'src: 'tokens>() -> impl Parser<
|
|||||||
))
|
))
|
||||||
.boxed();
|
.boxed();
|
||||||
|
|
||||||
choice([r#enum, logic, identifier_expression, list, basic_value])
|
choice((r#enum, logic, identifier_expression, list, basic_value))
|
||||||
});
|
});
|
||||||
|
|
||||||
let statement = recursive(|statement| {
|
let statement = recursive(|statement| {
|
||||||
@ -112,11 +112,23 @@ fn parser<'tokens, 'src: 'tokens>() -> impl Parser<
|
|||||||
.map(|expression| Statement::Expression(expression))
|
.map(|expression| Statement::Expression(expression))
|
||||||
.boxed();
|
.boxed();
|
||||||
|
|
||||||
|
let type_specification = just(Token::Control(":")).ignore_then(choice((
|
||||||
|
just(Token::Keyword("bool")).to(Type::Boolean),
|
||||||
|
just(Token::Keyword("float")).to(Type::Float),
|
||||||
|
just(Token::Keyword("int")).to(Type::Integer),
|
||||||
|
just(Token::Keyword("range")).to(Type::Range),
|
||||||
|
just(Token::Keyword("str")).to(Type::String),
|
||||||
|
identifier
|
||||||
|
.clone()
|
||||||
|
.map(|identifier| Type::Custom(identifier)),
|
||||||
|
)));
|
||||||
|
|
||||||
let assignment = identifier
|
let assignment = identifier
|
||||||
|
.then(type_specification.clone().or_not())
|
||||||
.then_ignore(just(Token::Operator("=")))
|
.then_ignore(just(Token::Operator("=")))
|
||||||
.then(statement.clone())
|
.then(statement.clone())
|
||||||
.map(|(identifier, statement)| {
|
.map(|((identifier, r#type), statement)| {
|
||||||
Statement::Assignment(Assignment::new(identifier, statement))
|
Statement::Assignment(Assignment::new(identifier, r#type, statement))
|
||||||
})
|
})
|
||||||
.boxed();
|
.boxed();
|
||||||
|
|
||||||
@ -128,7 +140,7 @@ fn parser<'tokens, 'src: 'tokens>() -> impl Parser<
|
|||||||
.map(|statements| Statement::Block(Block::new(statements)))
|
.map(|statements| Statement::Block(Block::new(statements)))
|
||||||
.boxed();
|
.boxed();
|
||||||
|
|
||||||
choice([assignment, expression_statement, block])
|
choice((assignment, expression_statement, block))
|
||||||
});
|
});
|
||||||
|
|
||||||
statement
|
statement
|
||||||
@ -225,11 +237,36 @@ mod tests {
|
|||||||
parse(&lex("foobar = 1").unwrap()).unwrap()[0].0,
|
parse(&lex("foobar = 1").unwrap()).unwrap()[0].0,
|
||||||
Statement::Assignment(Assignment::new(
|
Statement::Assignment(Assignment::new(
|
||||||
Identifier::new("foobar"),
|
Identifier::new("foobar"),
|
||||||
|
None,
|
||||||
Statement::Expression(Expression::Value(ValueNode::Integer(1)))
|
Statement::Expression(Expression::Value(ValueNode::Integer(1)))
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn assignment_with_type() {
|
||||||
|
assert_eq!(
|
||||||
|
parse(&lex("foobar: int = 1").unwrap()).unwrap()[0].0,
|
||||||
|
Statement::Assignment(Assignment::new(
|
||||||
|
Identifier::new("foobar"),
|
||||||
|
Some(Type::Integer),
|
||||||
|
Statement::Expression(Expression::Value(ValueNode::Integer(1)))
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
parse(&lex("foobar: Foo = Foo::Bar").unwrap()).unwrap()[0].0,
|
||||||
|
Statement::Assignment(Assignment::new(
|
||||||
|
Identifier::new("foobar"),
|
||||||
|
Some(Type::Custom(Identifier::new("Foo"))),
|
||||||
|
Statement::Expression(Expression::Value(ValueNode::Enum(
|
||||||
|
Identifier::new("Foo"),
|
||||||
|
Identifier::new("Bar")
|
||||||
|
)))
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn logic() {
|
fn logic() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -5,7 +5,7 @@ use std::{
|
|||||||
sync::{Arc, OnceLock},
|
sync::{Arc, OnceLock},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{abstract_tree::Identifier, error::RuntimeError};
|
use crate::{abstract_tree::Identifier, error::ValidationError};
|
||||||
|
|
||||||
pub static NONE: OnceLock<Value> = OnceLock::new();
|
pub static NONE: OnceLock<Value> = OnceLock::new();
|
||||||
|
|
||||||
@ -49,12 +49,12 @@ impl Value {
|
|||||||
Value(Arc::new(ValueInner::Enum(name, variant)))
|
Value(Arc::new(ValueInner::Enum(name, variant)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_boolean(&self) -> Result<bool, RuntimeError> {
|
pub fn as_boolean(&self) -> Result<bool, ValidationError> {
|
||||||
if let ValueInner::Boolean(boolean) = self.0.as_ref() {
|
if let ValueInner::Boolean(boolean) = self.0.as_ref() {
|
||||||
return Ok(*boolean);
|
return Ok(*boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(RuntimeError::ExpectedBoolean)
|
Err(ValidationError::ExpectedBoolean)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user