Implement serde for Value; Rework comment parsing

This commit is contained in:
Jeff 2024-06-19 03:32:51 -04:00
parent d37c618ead
commit 859d8db384
6 changed files with 429 additions and 112 deletions

View File

@ -65,11 +65,7 @@ impl AbstractNode for Assignment {
.. ..
} = function_type } = function_type
{ {
if let Type::Generic { if let Type::Generic { identifier, .. } = *return_type {
identifier,
concrete_type,
} = *return_type
{
let returned_parameter = type_parameters let returned_parameter = type_parameters
.into_iter() .into_iter()
.find(|parameter| parameter == &identifier); .find(|parameter| parameter == &identifier);

View File

@ -24,7 +24,7 @@ impl<'src> Display for Token<'src> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
Token::Boolean(boolean) => write!(f, "{boolean}"), Token::Boolean(boolean) => write!(f, "{boolean}"),
Token::Comment(comment) => write!(f, "# {comment}"), Token::Comment(comment) => write!(f, "// {comment}"),
Token::Integer(integer) => write!(f, "{integer}"), Token::Integer(integer) => write!(f, "{integer}"),
Token::Float(float) => write!(f, "{float}"), Token::Float(float) => write!(f, "{float}"),
Token::String(string) => write!(f, "{string}"), Token::String(string) => write!(f, "{string}"),

View File

@ -204,96 +204,109 @@ impl InterpreterError {
for error in self.errors { for error in self.errors {
let (mut builder, validation_error) = match error { let (mut builder, validation_error) = match error {
DustError::Lex { DustError::Lex {
expected, expected,
span, span,
reason, reason,
} => { } => {
let description = if expected.is_empty() { let description = if expected.is_empty() {
"Invalid character.".to_string() "Invalid character.".to_string()
} else { } else {
format!("Expected {expected}.") format!("Expected {expected}.")
}; };
( (
Report::build( Report::build(
ReportKind::Custom("Lexing Error", Color::Yellow), ReportKind::Custom("Lexing Error", Color::Yellow),
self.source_id.clone(), self.source_id.clone(),
span.1, span.1,
)
.with_message(description)
.with_label(
Label::new((self.source_id.clone(), span.0..span.1))
.with_message(reason)
.with_color(Color::Red),
),
None,
) )
.with_message(description) }
.with_label( DustError::Parse {
Label::new((self.source_id.clone(), span.0..span.1)) expected,
.with_message(reason) span,
.with_color(Color::Red), found,
), } => {
None, let description = if expected.is_empty() {
) "Invalid token.".to_string()
} } else {
DustError::Parse { format!("Expected {expected}.")
expected, };
span, let found = found
found, .unwrap_or_else(|| "End of input".to_string())
} => { .fg(token_color);
let description = if expected.is_empty() {
"Invalid token.".to_string()
} else {
format!("Expected {expected}.")
};
let found = found.unwrap_or_else(|| "End of input".to_string()).fg(token_color);
( (
Report::build( Report::build(
ReportKind::Custom("Parsing Error", Color::Yellow), ReportKind::Custom("Parsing Error", Color::Yellow),
self.source_id.clone(), self.source_id.clone(),
span.1, span.1,
)
.with_message(description)
.with_label(
Label::new((self.source_id.clone(), span.0..span.1))
.with_message(format!("{found} is not valid in this position."))
.with_color(Color::Red),
),
None,
) )
.with_message(description) }
.with_label( DustError::Validation { error, position } => (
Label::new((self.source_id.clone(), span.0..span.1)) Report::build(
.with_message(format!("{found} is not valid in this position.")) ReportKind::Custom("Validation Error", Color::Magenta),
.with_color(Color::Red), self.source_id.clone(),
position.1,
)
.with_message("The syntax is valid but this code would cause an error.")
.with_note(
"This error was detected by the interpreter before running the code.",
), ),
None, Some(error),
)
}
DustError::Validation { error, position } => (
Report::build(
ReportKind::Custom("Validation Error", Color::Magenta),
self.source_id.clone(),
position.1,
)
.with_message("The syntax is valid but this code would cause an error.")
.with_note("This error was detected by the interpreter before running the code."),
Some(error),
),
DustError::Runtime { error, position } => (
Report::build(
ReportKind::Custom("Runtime Error", Color::Red),
self.source_id.clone(),
position.1,
)
.with_message("An error occured that forced the program to exit.")
.with_note(
"There may be unexpected side-effects because the program could not finish.",
)
.with_help(
"This is the interpreter's fault. Please submit a bug with this error message.",
)
.with_label(
Label::new((self.source_id.clone(), position.0..position.1)).with_message("Runtime error occured here.")
), ),
if let RuntimeError::ValidationFailure(validation_error) = error { DustError::Runtime { error, position } => {
Some(validation_error) let error_message = match &error {
} else { RuntimeError::Io(_) => todo!(),
None RuntimeError::RwLockPoison(_) => todo!(),
}, RuntimeError::ValidationFailure(_) => todo!(),
), RuntimeError::SerdeJson(serde_json_error) => serde_json_error.to_string(),
}; };
(
Report::build(
ReportKind::Custom("Runtime Error", Color::Red),
self.source_id.clone(),
position.1,
)
.with_message("An error occured that forced the program to exit.")
.with_note(
"There may be unexpected side-effects because the program could not finish.",
)
.with_help(
"This is the interpreter's fault. Please submit a bug with this error message.",
)
.with_label(
Label::new((self.source_id.clone(), position.0..position.1)).with_message(error_message)
),
if let RuntimeError::ValidationFailure(validation_error) = error {
Some(validation_error)
} else {
None
},
)
}
};
if let Some(validation_error) = validation_error { if let Some(validation_error) = validation_error {
match validation_error { match validation_error {
ValidationError::CannotAssignToNone(postion) => { ValidationError::CannotAssignToNone(postion) => {
builder.add_label( builder.add_label(
Label::new((self.source_id.clone(), postion.0..postion.1)) Label::new((self.source_id.clone(), postion.0..postion.1))

View File

@ -33,6 +33,9 @@ pub fn parse<'src>(
pub fn parser<'src>( pub fn parser<'src>(
allow_built_ins: bool, allow_built_ins: bool,
) -> impl Parser<'src, ParserInput<'src>, Vec<Statement>, ParserExtra<'src>> { ) -> impl Parser<'src, ParserInput<'src>, Vec<Statement>, ParserExtra<'src>> {
let comment = select_ref! {
Token::Comment(_) => {}
};
let identifiers: RefCell<HashMap<&str, Identifier>> = RefCell::new(HashMap::new()); let identifiers: RefCell<HashMap<&str, Identifier>> = RefCell::new(HashMap::new());
let identifier = select! { let identifier = select! {
Token::Identifier(text) => { Token::Identifier(text) => {
@ -527,6 +530,7 @@ pub fn parser<'src>(
basic_value, basic_value,
identifier_expression, identifier_expression,
)) ))
// .delimited_by(comment.clone().or_not(), comment.or_not())
}); });
let expression_statement = expression let expression_statement = expression
@ -621,27 +625,24 @@ pub fn parser<'src>(
) )
}); });
choice(( comment
async_block, .repeated()
if_else, .or_not()
assignment, .ignore_then(choice((
expression_statement, async_block,
r#break, if_else,
block_statement, assignment,
r#loop, expression_statement,
r#while, r#break,
type_assignment, block_statement,
)) r#loop,
.then_ignore(just(Token::Control(Control::Semicolon)).or_not()) r#while,
type_assignment,
)))
.then_ignore(just(Token::Control(Control::Semicolon)).or_not())
}); });
select_ref! { statement.repeated().collect()
Token::Comment(_) => {}
}
.or_not()
.ignore_then(statement)
.repeated()
.collect()
} }
#[cfg(test)] #[cfg(test)]

View File

@ -6,7 +6,11 @@ use std::{
sync::Arc, sync::Arc,
}; };
use serde::{Deserialize, Serialize}; use serde::{
de::Visitor,
ser::{SerializeMap, SerializeSeq, SerializeStruct, SerializeTuple},
Deserialize, Deserializer, Serialize,
};
use crate::{ use crate::{
abstract_tree::{AbstractNode, Block, Evaluation, Type, WithPosition}, abstract_tree::{AbstractNode, Block, Evaluation, Type, WithPosition},
@ -184,20 +188,312 @@ impl Ord for Value {
} }
impl Serialize for Value { impl Serialize for Value {
fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
S: serde::Serializer, S: serde::Serializer,
{
match self.0.as_ref() {
ValueInner::Boolean(boolean) => serializer.serialize_bool(*boolean),
ValueInner::Float(float) => serializer.serialize_f64(*float),
ValueInner::Function(Function {
type_parameters,
value_parameters,
return_type,
body,
}) => {
let mut struct_ser = serializer.serialize_struct("Function", 4)?;
struct_ser.serialize_field("type_parameters", type_parameters)?;
struct_ser.serialize_field("value_parameters", value_parameters)?;
struct_ser.serialize_field("return_type", return_type)?;
struct_ser.serialize_field("body", body)?;
struct_ser.end()
}
ValueInner::Integer(integer) => serializer.serialize_i64(*integer),
ValueInner::List(list) => {
let mut list_ser = serializer.serialize_seq(Some(list.len()))?;
for item in list {
list_ser.serialize_element(&item.node)?;
}
list_ser.end()
}
ValueInner::Map(map) => {
let mut map_ser = serializer.serialize_map(Some(map.len()))?;
for (identifier, value) in map {
map_ser.serialize_entry(identifier, value)?;
}
map_ser.end()
}
ValueInner::Range(range) => {
let mut tuple_ser = serializer.serialize_tuple(2)?;
tuple_ser.serialize_element(&range.start)?;
tuple_ser.serialize_element(&range.end)?;
tuple_ser.end()
}
ValueInner::String(string) => serializer.serialize_str(string),
ValueInner::Structure { name, fields } => {
let mut struct_ser = serializer.serialize_struct("Structure", 2)?;
struct_ser.serialize_field("name", name)?;
struct_ser.serialize_field("fields", fields)?;
struct_ser.end()
}
}
}
}
struct ValueVisitor;
impl<'de> Visitor<'de> for ValueVisitor {
type Value = Value;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter
.write_str("a boolean, float, function, integer, list, map, range, string or structure")
}
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Err(serde::de::Error::invalid_type(
serde::de::Unexpected::Bool(v),
&self,
))
}
fn visit_i8<E>(self, v: i8) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_i64(v as i64)
}
fn visit_i16<E>(self, v: i16) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_i64(v as i64)
}
fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_i64(v as i64)
}
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::integer(v))
}
fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
where
E: serde::de::Error,
{ {
todo!() todo!()
} }
fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_u64(v as u64)
}
fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_u64(v as u64)
}
fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_u64(v as u64)
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::integer(v as i64))
}
fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
todo!()
}
fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_f64(v as f64)
}
fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Err(serde::de::Error::invalid_type(
serde::de::Unexpected::Float(v),
&self,
))
}
fn visit_char<E>(self, v: char) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_str(v.encode_utf8(&mut [0u8; 4]))
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Err(serde::de::Error::invalid_type(
serde::de::Unexpected::Str(v),
&self,
))
}
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_str(v)
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_str(&v)
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Err(serde::de::Error::invalid_type(
serde::de::Unexpected::Bytes(v),
&self,
))
}
fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_bytes(v)
}
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_bytes(&v)
}
fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Err(serde::de::Error::invalid_type(
serde::de::Unexpected::Option,
&self,
))
}
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
let _ = deserializer;
Err(serde::de::Error::invalid_type(
serde::de::Unexpected::Option,
&self,
))
}
fn visit_unit<E>(self) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Err(serde::de::Error::invalid_type(
serde::de::Unexpected::Unit,
&self,
))
}
fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
let _ = deserializer;
Err(serde::de::Error::invalid_type(
serde::de::Unexpected::NewtypeStruct,
&self,
))
}
fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
let _ = seq;
Err(serde::de::Error::invalid_type(
serde::de::Unexpected::Seq,
&self,
))
}
fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
where
A: serde::de::MapAccess<'de>,
{
let _ = map;
Err(serde::de::Error::invalid_type(
serde::de::Unexpected::Map,
&self,
))
}
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
where
A: serde::de::EnumAccess<'de>,
{
let _ = data;
Err(serde::de::Error::invalid_type(
serde::de::Unexpected::Enum,
&self,
))
}
} }
impl<'de> Deserialize<'de> for Value { impl<'de> Deserialize<'de> for Value {
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: serde::Deserializer<'de>, D: Deserializer<'de>,
{ {
todo!() deserializer.deserialize_any(ValueVisitor)
} }
} }

View File

@ -1,5 +1,16 @@
// This function returns its argument.
foo = fn |T| (x: T) -> T { x } foo = fn |T| (x: T) -> T { x }
bar: str = foo::(str)::("hi")
// Use turbofish to supply type information.
bar = foo::(str)::("hi")
// Use type annotation
baz: str = foo("hi") baz: str = foo("hi")
// The `json.parse` function takes a string and returns the specified type
// Use turbofish
x = json.parse::(int)::("1") x = json.parse::(int)::("1")
// Use type annotation
x: int = json.parse("1") x: int = json.parse("1")