Improve named type parsing; Clean up
This commit is contained in:
parent
177888c962
commit
936b1f5de9
@ -10,7 +10,7 @@ use crate::{
|
|||||||
|
|
||||||
use super::{AbstractNode, Action, Type};
|
use super::{AbstractNode, Action, Type};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct Identifier(Arc<String>);
|
pub struct Identifier(Arc<String>);
|
||||||
|
|
||||||
impl Identifier {
|
impl Identifier {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
|
use clap::error::Result;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
abstract_tree::Identifier,
|
abstract_tree::Identifier,
|
||||||
context::Context,
|
context::Context,
|
||||||
@ -22,7 +24,6 @@ pub enum Type {
|
|||||||
ListOf(Box<Type>),
|
ListOf(Box<Type>),
|
||||||
ListExact(Vec<Type>),
|
ListExact(Vec<Type>),
|
||||||
Map,
|
Map,
|
||||||
Named(Identifier),
|
|
||||||
None,
|
None,
|
||||||
Range,
|
Range,
|
||||||
String,
|
String,
|
||||||
@ -75,6 +76,32 @@ impl Type {
|
|||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
(
|
||||||
|
Type::Structure {
|
||||||
|
name: left_name,
|
||||||
|
fields: left_fields,
|
||||||
|
},
|
||||||
|
Type::Structure {
|
||||||
|
name: right_name,
|
||||||
|
fields: right_fields,
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
if left_name == right_name {
|
||||||
|
for ((left_field_name, left_type), (right_field_name, right_type)) in
|
||||||
|
left_fields.iter().zip(right_fields.iter())
|
||||||
|
{
|
||||||
|
if left_field_name != right_field_name || left_type.node != right_type.node
|
||||||
|
{
|
||||||
|
return Err(TypeConflict {
|
||||||
|
actual: other.clone(),
|
||||||
|
expected: self.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
(
|
(
|
||||||
Type::Function {
|
Type::Function {
|
||||||
parameter_types: left_parameters,
|
parameter_types: left_parameters,
|
||||||
@ -89,27 +116,6 @@ impl Type {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(Type::Named(left), Type::Named(right)) => {
|
|
||||||
if left == right {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(
|
|
||||||
Type::Named(named),
|
|
||||||
Type::Structure {
|
|
||||||
name: struct_name, ..
|
|
||||||
},
|
|
||||||
)
|
|
||||||
| (
|
|
||||||
Type::Structure {
|
|
||||||
name: struct_name, ..
|
|
||||||
},
|
|
||||||
Type::Named(named),
|
|
||||||
) => {
|
|
||||||
if named == struct_name {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,8 +178,7 @@ impl Display for Type {
|
|||||||
|
|
||||||
write!(f, ") : {return_type}")
|
write!(f, ") : {return_type}")
|
||||||
}
|
}
|
||||||
Type::Structure { .. } => todo!(),
|
Type::Structure { name, .. } => write!(f, "{name}"),
|
||||||
Type::Named(name) => write!(f, "{name}"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
use std::{cmp::Ordering, collections::BTreeMap, ops::Range};
|
use std::{cmp::Ordering, collections::BTreeMap, ops::Range};
|
||||||
|
|
||||||
use chumsky::container::Container;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
context::Context,
|
context::Context,
|
||||||
error::{RuntimeError, ValidationError},
|
error::{RuntimeError, ValidationError},
|
||||||
@ -145,7 +143,7 @@ impl AbstractNode for ValueNode {
|
|||||||
{
|
{
|
||||||
let types = if let Some(r#type) = context.get_type(name)? {
|
let types = if let Some(r#type) = context.get_type(name)? {
|
||||||
if let Type::Structure {
|
if let Type::Structure {
|
||||||
name,
|
name: _,
|
||||||
fields: types,
|
fields: types,
|
||||||
} = r#type
|
} = r#type
|
||||||
{
|
{
|
||||||
@ -319,8 +317,16 @@ impl Ord for ValueNode {
|
|||||||
name: right_name,
|
name: right_name,
|
||||||
fields: right_fields,
|
fields: right_fields,
|
||||||
},
|
},
|
||||||
) => todo!(),
|
) => {
|
||||||
(Structure { name, fields }, _) => todo!(),
|
let name_cmp = left_name.cmp(right_name);
|
||||||
|
|
||||||
|
if name_cmp.is_eq() {
|
||||||
|
left_fields.cmp(right_fields)
|
||||||
|
} else {
|
||||||
|
name_cmp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Structure { .. }, _) => Ordering::Greater,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,13 +79,7 @@ impl Context {
|
|||||||
pub fn get_type(&self, identifier: &Identifier) -> Result<Option<Type>, ValidationError> {
|
pub fn get_type(&self, identifier: &Identifier) -> Result<Option<Type>, ValidationError> {
|
||||||
if let Some(value_data) = self.inner.read()?.get(identifier) {
|
if let Some(value_data) = self.inner.read()?.get(identifier) {
|
||||||
let r#type = match value_data {
|
let r#type = match value_data {
|
||||||
ValueData::Type(r#type) => {
|
ValueData::Type(r#type) => r#type.clone(),
|
||||||
if let Type::Named(name) = r#type {
|
|
||||||
return self.get_type(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
r#type.clone()
|
|
||||||
}
|
|
||||||
ValueData::Value(value) => value.r#type(self)?,
|
ValueData::Value(value) => value.r#type(self)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -13,10 +13,12 @@ pub enum Error {
|
|||||||
Parse {
|
Parse {
|
||||||
expected: String,
|
expected: String,
|
||||||
span: (usize, usize),
|
span: (usize, usize),
|
||||||
|
reason: String,
|
||||||
},
|
},
|
||||||
Lex {
|
Lex {
|
||||||
expected: String,
|
expected: String,
|
||||||
span: (usize, usize),
|
span: (usize, usize),
|
||||||
|
reason: String,
|
||||||
},
|
},
|
||||||
Runtime {
|
Runtime {
|
||||||
error: RuntimeError,
|
error: RuntimeError,
|
||||||
@ -29,11 +31,15 @@ pub enum Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Error {
|
impl Error {
|
||||||
pub fn build_report(self, source: &str) -> Vec<u8> {
|
pub fn build_report(self, source: &str) -> Result<Vec<u8>, io::Error> {
|
||||||
let (mut builder, validation_error, error_position) = match self {
|
let (mut builder, validation_error, error_position) = match self {
|
||||||
Error::Parse { expected, span } => {
|
Error::Parse {
|
||||||
let message = if expected.is_empty() {
|
expected,
|
||||||
"Invalid character.".to_string()
|
span,
|
||||||
|
reason,
|
||||||
|
} => {
|
||||||
|
let description = if expected.is_empty() {
|
||||||
|
"Invalid token.".to_string()
|
||||||
} else {
|
} else {
|
||||||
format!("Expected {expected}.")
|
format!("Expected {expected}.")
|
||||||
};
|
};
|
||||||
@ -44,31 +50,37 @@ impl Error {
|
|||||||
"input",
|
"input",
|
||||||
span.1,
|
span.1,
|
||||||
)
|
)
|
||||||
|
.with_message(description)
|
||||||
.with_label(
|
.with_label(
|
||||||
Label::new(("input", span.0..span.1))
|
Label::new(("input", span.0..span.1))
|
||||||
.with_message(message)
|
.with_message(reason)
|
||||||
.with_color(Color::Red),
|
.with_color(Color::Red),
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
span.into(),
|
span.into(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Error::Lex { expected, span } => {
|
Error::Lex {
|
||||||
let message = if expected.is_empty() {
|
expected,
|
||||||
"Invalid token.".to_string()
|
span,
|
||||||
|
reason,
|
||||||
|
} => {
|
||||||
|
let description = if expected.is_empty() {
|
||||||
|
"Invalid character.".to_string()
|
||||||
} else {
|
} else {
|
||||||
format!("Expected {expected}.")
|
format!("Expected {expected}.")
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
Report::build(
|
Report::build(
|
||||||
ReportKind::Custom("Dust Error", Color::White),
|
ReportKind::Custom("Lexing Error", Color::White),
|
||||||
"input",
|
"input",
|
||||||
span.1,
|
span.1,
|
||||||
)
|
)
|
||||||
|
.with_message(description)
|
||||||
.with_label(
|
.with_label(
|
||||||
Label::new(("input", span.0..span.1))
|
Label::new(("input", span.0..span.1))
|
||||||
.with_message(message)
|
.with_message(reason)
|
||||||
.with_color(Color::Red),
|
.with_color(Color::Red),
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
@ -188,9 +200,9 @@ impl Error {
|
|||||||
|
|
||||||
builder
|
builder
|
||||||
.finish()
|
.finish()
|
||||||
.write_for_stdout(sources([("input", source)]), &mut output);
|
.write_for_stdout(sources([("input", source)]), &mut output)?;
|
||||||
|
|
||||||
output
|
Ok(output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,6 +211,7 @@ impl From<Rich<'_, char>> for Error {
|
|||||||
Error::Lex {
|
Error::Lex {
|
||||||
expected: error.expected().map(|error| error.to_string()).collect(),
|
expected: error.expected().map(|error| error.to_string()).collect(),
|
||||||
span: (error.span().start(), error.span().end()),
|
span: (error.span().start(), error.span().end()),
|
||||||
|
reason: error.reason().to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -208,6 +221,7 @@ impl<'src> From<Rich<'_, Token<'src>>> for Error {
|
|||||||
Error::Parse {
|
Error::Parse {
|
||||||
expected: error.expected().map(|error| error.to_string()).collect(),
|
expected: error.expected().map(|error| error.to_string()).collect(),
|
||||||
span: (error.span().start(), error.span().end()),
|
span: (error.span().start(), error.span().end()),
|
||||||
|
reason: error.reason().to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::{cell::RefCell, collections::HashMap};
|
use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
||||||
|
|
||||||
use chumsky::{input::SpannedInput, pratt::*, prelude::*};
|
use chumsky::{input::SpannedInput, pratt::*, prelude::*};
|
||||||
|
|
||||||
@ -32,6 +32,8 @@ pub fn parser<'src>() -> impl Parser<
|
|||||||
extra::Err<Rich<'src, Token<'src>, SimpleSpan>>,
|
extra::Err<Rich<'src, Token<'src>, SimpleSpan>>,
|
||||||
> {
|
> {
|
||||||
let identifiers: RefCell<HashMap<&str, Identifier>> = RefCell::new(HashMap::new());
|
let identifiers: RefCell<HashMap<&str, Identifier>> = RefCell::new(HashMap::new());
|
||||||
|
let _custom_types: Rc<RefCell<HashMap<Identifier, Type>>> =
|
||||||
|
Rc::new(RefCell::new(HashMap::new()));
|
||||||
|
|
||||||
let identifier = select! {
|
let identifier = select! {
|
||||||
Token::Identifier(text) => {
|
Token::Identifier(text) => {
|
||||||
@ -61,6 +63,7 @@ pub fn parser<'src>() -> impl Parser<
|
|||||||
}
|
}
|
||||||
.map_with(|value, state| Expression::Value(value).with_position(state.span()));
|
.map_with(|value, state| Expression::Value(value).with_position(state.span()));
|
||||||
|
|
||||||
|
let custom_types = _custom_types.clone();
|
||||||
let r#type = recursive(|r#type| {
|
let r#type = recursive(|r#type| {
|
||||||
let function_type = r#type
|
let function_type = r#type
|
||||||
.clone()
|
.clone()
|
||||||
@ -106,13 +109,22 @@ pub fn parser<'src>() -> impl Parser<
|
|||||||
just(Token::Keyword("range")).to(Type::Range),
|
just(Token::Keyword("range")).to(Type::Range),
|
||||||
just(Token::Keyword("str")).to(Type::String),
|
just(Token::Keyword("str")).to(Type::String),
|
||||||
just(Token::Keyword("list")).to(Type::List),
|
just(Token::Keyword("list")).to(Type::List),
|
||||||
identifier.clone().map(|identifier| Type::Named(identifier)),
|
identifier.clone().try_map(move |identifier, span| {
|
||||||
|
custom_types
|
||||||
|
.borrow()
|
||||||
|
.get(&identifier)
|
||||||
|
.cloned()
|
||||||
|
.ok_or_else(|| {
|
||||||
|
Rich::custom(span, format!("There is no type named {identifier}."))
|
||||||
|
})
|
||||||
|
}),
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
.map_with(|r#type, state| r#type.with_position(state.span()));
|
.map_with(|r#type, state| r#type.with_position(state.span()));
|
||||||
|
|
||||||
let type_specification = just(Token::Control(Control::Colon)).ignore_then(r#type.clone());
|
let type_specification = just(Token::Control(Control::Colon)).ignore_then(r#type.clone());
|
||||||
|
|
||||||
|
let custom_types = _custom_types.clone();
|
||||||
let positioned_statement = recursive(|positioned_statement| {
|
let positioned_statement = recursive(|positioned_statement| {
|
||||||
let block = positioned_statement
|
let block = positioned_statement
|
||||||
.clone()
|
.clone()
|
||||||
@ -454,15 +466,22 @@ pub fn parser<'src>() -> impl Parser<
|
|||||||
structure_field_definition
|
structure_field_definition
|
||||||
.separated_by(just(Token::Control(Control::Comma)))
|
.separated_by(just(Token::Control(Control::Comma)))
|
||||||
.allow_trailing()
|
.allow_trailing()
|
||||||
.collect()
|
.collect::<Vec<(Identifier, WithPosition<Type>)>>()
|
||||||
.delimited_by(
|
.delimited_by(
|
||||||
just(Token::Control(Control::CurlyOpen)),
|
just(Token::Control(Control::CurlyOpen)),
|
||||||
just(Token::Control(Control::CurlyClose)),
|
just(Token::Control(Control::CurlyClose)),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.map_with(|(name, fields), state| {
|
.map_with(move |(name, fields), state| {
|
||||||
Statement::StructureDefinition(StructureDefinition::new(name, fields))
|
let definition = StructureDefinition::new(name.clone(), fields.clone());
|
||||||
.with_position(state.span())
|
let r#type = Type::Structure {
|
||||||
|
name: name.clone(),
|
||||||
|
fields,
|
||||||
|
};
|
||||||
|
|
||||||
|
custom_types.as_ref().borrow_mut().insert(name, r#type);
|
||||||
|
|
||||||
|
Statement::StructureDefinition(definition).with_position(state.span())
|
||||||
});
|
});
|
||||||
|
|
||||||
choice((
|
choice((
|
||||||
|
@ -79,43 +79,7 @@ impl Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn r#type(&self, context: &Context) -> Result<Type, ValidationError> {
|
pub fn r#type(&self, context: &Context) -> Result<Type, ValidationError> {
|
||||||
let r#type = match self.0.as_ref() {
|
self.0.r#type(context)
|
||||||
ValueInner::Boolean(_) => Type::Boolean,
|
|
||||||
ValueInner::Float(_) => Type::Float,
|
|
||||||
ValueInner::Integer(_) => Type::Integer,
|
|
||||||
ValueInner::List(values) => {
|
|
||||||
let mut types = Vec::with_capacity(values.len());
|
|
||||||
|
|
||||||
for value in values {
|
|
||||||
types.push(value.r#type(context)?);
|
|
||||||
}
|
|
||||||
|
|
||||||
Type::ListExact(types)
|
|
||||||
}
|
|
||||||
ValueInner::Map(_) => Type::Map,
|
|
||||||
ValueInner::Range(_) => Type::Range,
|
|
||||||
ValueInner::String(_) => Type::String,
|
|
||||||
ValueInner::Function(function) => match function {
|
|
||||||
Function::Parsed(parsed_function) => Type::Function {
|
|
||||||
parameter_types: parsed_function
|
|
||||||
.parameters
|
|
||||||
.iter()
|
|
||||||
.map(|(_, r#type)| r#type.node.clone())
|
|
||||||
.collect(),
|
|
||||||
return_type: Box::new(parsed_function.return_type.node.clone()),
|
|
||||||
},
|
|
||||||
Function::BuiltIn(built_in_function) => built_in_function.r#type(),
|
|
||||||
},
|
|
||||||
ValueInner::Structure { name, .. } => {
|
|
||||||
if let Some(r#type) = context.get_type(name)? {
|
|
||||||
r#type
|
|
||||||
} else {
|
|
||||||
return Err(ValidationError::TypeNotFound(name.clone()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(r#type)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_boolean(&self) -> Option<bool> {
|
pub fn as_boolean(&self) -> Option<bool> {
|
||||||
@ -232,6 +196,48 @@ pub enum ValueInner {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ValueInner {
|
||||||
|
pub fn r#type(&self, context: &Context) -> Result<Type, ValidationError> {
|
||||||
|
let r#type = match self {
|
||||||
|
ValueInner::Boolean(_) => Type::Boolean,
|
||||||
|
ValueInner::Float(_) => Type::Float,
|
||||||
|
ValueInner::Integer(_) => Type::Integer,
|
||||||
|
ValueInner::List(values) => {
|
||||||
|
let mut types = Vec::with_capacity(values.len());
|
||||||
|
|
||||||
|
for value in values {
|
||||||
|
types.push(value.r#type(context)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Type::ListExact(types)
|
||||||
|
}
|
||||||
|
ValueInner::Map(_) => Type::Map,
|
||||||
|
ValueInner::Range(_) => Type::Range,
|
||||||
|
ValueInner::String(_) => Type::String,
|
||||||
|
ValueInner::Function(function) => match function {
|
||||||
|
Function::Parsed(parsed_function) => Type::Function {
|
||||||
|
parameter_types: parsed_function
|
||||||
|
.parameters
|
||||||
|
.iter()
|
||||||
|
.map(|(_, r#type)| r#type.node.clone())
|
||||||
|
.collect(),
|
||||||
|
return_type: Box::new(parsed_function.return_type.node.clone()),
|
||||||
|
},
|
||||||
|
Function::BuiltIn(built_in_function) => built_in_function.r#type(),
|
||||||
|
},
|
||||||
|
ValueInner::Structure { name, .. } => {
|
||||||
|
if let Some(r#type) = context.get_type(name)? {
|
||||||
|
r#type
|
||||||
|
} else {
|
||||||
|
return Err(ValidationError::TypeNotFound(name.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(r#type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Eq for ValueInner {}
|
impl Eq for ValueInner {}
|
||||||
|
|
||||||
impl PartialOrd for ValueInner {
|
impl PartialOrd for ValueInner {
|
||||||
@ -397,7 +403,7 @@ impl BuiltInFunction {
|
|||||||
BuiltInFunction::IntParse => {
|
BuiltInFunction::IntParse => {
|
||||||
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 = string.parse();
|
||||||
|
|
||||||
todo!()
|
todo!()
|
||||||
|
@ -87,7 +87,7 @@ pub fn run_shell(context: Context) {
|
|||||||
Ok(None) => {}
|
Ok(None) => {}
|
||||||
Err(errors) => {
|
Err(errors) => {
|
||||||
for error in errors {
|
for error in errors {
|
||||||
let report = error.build_report(&buffer);
|
let report = error.build_report(&buffer).unwrap();
|
||||||
|
|
||||||
stderr().write_all(&report).unwrap();
|
stderr().write_all(&report).unwrap();
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
Err(errors) => {
|
Err(errors) => {
|
||||||
for error in errors {
|
for error in errors {
|
||||||
let report = error.build_report(&source);
|
let report = error.build_report(&source).unwrap();
|
||||||
|
|
||||||
stderr().write_all(&report).unwrap();
|
stderr().write_all(&report).unwrap();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user