mirror of
https://github.com/Dummi26/mers.git
synced 2025-12-16 03:57:50 +01:00
add objects and object types
This commit is contained in:
@@ -180,15 +180,24 @@ impl Source {
|
||||
self.i += ch.len_utf8();
|
||||
Some(ch)
|
||||
}
|
||||
fn word_splitter(ch: char) -> bool {
|
||||
fn word_splitter_no_colon(ch: char) -> bool {
|
||||
ch.is_whitespace() || ".,;[](){}/<".contains(ch)
|
||||
}
|
||||
fn word_splitter(ch: char) -> bool {
|
||||
Self::word_splitter_no_colon(ch) || ch == ':'
|
||||
}
|
||||
pub fn peek_word(&self) -> &str {
|
||||
self.src[self.i..]
|
||||
.split(Self::word_splitter)
|
||||
.next()
|
||||
.unwrap_or("")
|
||||
}
|
||||
pub fn peek_word_allow_colon(&self) -> &str {
|
||||
self.src[self.i..]
|
||||
.split(Self::word_splitter_no_colon)
|
||||
.next()
|
||||
.unwrap_or("")
|
||||
}
|
||||
pub fn next_word(&mut self) -> &str {
|
||||
self.end_sections();
|
||||
let word = self.src[self.i..]
|
||||
@@ -198,6 +207,15 @@ impl Source {
|
||||
self.i += word.len();
|
||||
word
|
||||
}
|
||||
pub fn next_word_allow_colon(&mut self) -> &str {
|
||||
self.end_sections();
|
||||
let word = self.src[self.i..]
|
||||
.split(Self::word_splitter_no_colon)
|
||||
.next()
|
||||
.unwrap_or("");
|
||||
self.i += word.len();
|
||||
word
|
||||
}
|
||||
pub fn peek_line(&self) -> &str {
|
||||
self.src[self.i..].lines().next().unwrap_or("")
|
||||
}
|
||||
|
||||
@@ -35,15 +35,15 @@ pub fn parse(
|
||||
);
|
||||
}
|
||||
src.skip_whitespace();
|
||||
if src.peek_word() == ":=" {
|
||||
src.next_word();
|
||||
if src.peek_word_allow_colon() == ":=" {
|
||||
src.next_word_allow_colon();
|
||||
// [[name] := statement]
|
||||
let statement = match parse(src, srca) {
|
||||
Ok(Some(v)) => v,
|
||||
Ok(None) => {
|
||||
return Err(CheckError::new()
|
||||
.src(vec![((pos_in_src, src.get_pos(), srca).into(), None)])
|
||||
.msg(format!("EOF after `[...]` type annotation")))
|
||||
.msg(format!("EOF after `[[...] := ...]` type definition")))
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
@@ -113,10 +113,10 @@ pub fn parse(
|
||||
};
|
||||
let mut pos_after_first = src.get_pos();
|
||||
src.skip_whitespace();
|
||||
match src.peek_word() {
|
||||
match src.peek_word_allow_colon() {
|
||||
":=" => {
|
||||
let pos_in_src = src.get_pos();
|
||||
src.next_word();
|
||||
src.next_word_allow_colon();
|
||||
let source = parse(src, srca)?.ok_or_else(|| {
|
||||
CheckError::new()
|
||||
.src(vec![((pos_in_src, src.get_pos(), srca).into(), None)])
|
||||
@@ -130,7 +130,7 @@ pub fn parse(
|
||||
}
|
||||
"=" => {
|
||||
let pos_in_src = src.get_pos();
|
||||
src.next_word();
|
||||
src.next_word_allow_colon();
|
||||
let source = parse(src, srca)?.ok_or_else(|| {
|
||||
CheckError::new()
|
||||
.src(vec![((pos_in_src, src.get_pos(), srca).into(), None)])
|
||||
@@ -144,7 +144,7 @@ pub fn parse(
|
||||
}
|
||||
"->" => {
|
||||
let pos_in_src = src.get_pos();
|
||||
src.next_word();
|
||||
src.next_word_allow_colon();
|
||||
let run = match parse(src, srca) {
|
||||
Ok(Some(v)) => v,
|
||||
Ok(None) => {
|
||||
@@ -303,8 +303,50 @@ pub fn parse_no_chain(
|
||||
}
|
||||
}
|
||||
Some('{') => {
|
||||
// try: is this an object?
|
||||
let pos_in_src = src.get_pos();
|
||||
src.next_char();
|
||||
let pos_in_src_after_bracket = src.get_pos();
|
||||
{
|
||||
let mut elems = vec![];
|
||||
loop {
|
||||
src.skip_whitespace();
|
||||
if src.peek_char() == Some('}') {
|
||||
src.next_char();
|
||||
return Ok(Some(Box::new(program::parsed::object::Object {
|
||||
pos_in_src: (pos_in_src, src.get_pos(), srca).into(),
|
||||
elems,
|
||||
})));
|
||||
}
|
||||
let name = src.next_word().to_owned();
|
||||
src.skip_whitespace();
|
||||
match src.next_char() {
|
||||
Some(':') => elems.push((
|
||||
name,
|
||||
match parse(src, srca) {
|
||||
Ok(Some(v)) => v,
|
||||
Ok(None) => {
|
||||
return Err(CheckError::new()
|
||||
.src(vec![((pos_in_src, src.get_pos(), srca).into(), None)])
|
||||
.msg(format!("EOF after `:` in object")))
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(CheckError::new()
|
||||
.src(vec![((pos_in_src, src.get_pos(), srca).into(), None)])
|
||||
.msg(format!("Error in statement after `:` in object"))
|
||||
.err(e))
|
||||
}
|
||||
},
|
||||
)),
|
||||
_ => {
|
||||
// not an object (or invalid syntax)
|
||||
src.set_pos(pos_in_src_after_bracket);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// if not an object
|
||||
let statements = parse_multiple(src, srca, "}")?;
|
||||
return Ok(Some(Box::new(program::parsed::block::Block {
|
||||
pos_in_src: (pos_in_src, src.get_pos(), srca).into(),
|
||||
|
||||
@@ -12,6 +12,7 @@ use super::Source;
|
||||
pub enum ParsedType {
|
||||
Reference(Vec<Self>),
|
||||
Tuple(Vec<Vec<Self>>),
|
||||
Object(Vec<(String, Vec<Self>)>),
|
||||
Type(String),
|
||||
TypeWithInfo(String, String),
|
||||
}
|
||||
@@ -54,6 +55,7 @@ pub fn parse_single_type(src: &mut Source, srca: &Arc<Source>) -> Result<ParsedT
|
||||
} else {
|
||||
loop {
|
||||
inner.push(parse_type(src, srca)?);
|
||||
src.skip_whitespace();
|
||||
match src.peek_char() {
|
||||
Some(')') => {
|
||||
src.next_char();
|
||||
@@ -82,6 +84,42 @@ pub fn parse_single_type(src: &mut Source, srca: &Arc<Source>) -> Result<ParsedT
|
||||
}
|
||||
ParsedType::Tuple(inner)
|
||||
}
|
||||
// Object
|
||||
Some('{') => {
|
||||
let pos_in_src = src.get_pos();
|
||||
src.next_char();
|
||||
src.section_begin("parse tuple's inner types".to_string());
|
||||
let mut inner = vec![];
|
||||
src.skip_whitespace();
|
||||
if let Some('}') = src.peek_char() {
|
||||
// empty object, don't even start the loop
|
||||
} else {
|
||||
loop {
|
||||
src.skip_whitespace();
|
||||
let field = src.next_word().to_owned();
|
||||
src.skip_whitespace();
|
||||
if src.next_char() != Some(':') {
|
||||
return Err(CheckError::new()
|
||||
.src(vec![((pos_in_src, src.get_pos(), srca).into(), None)])
|
||||
.msg(format!("Expected colon ':' in object type")));
|
||||
}
|
||||
src.skip_whitespace();
|
||||
inner.push((field, parse_type(src, srca)?));
|
||||
src.skip_whitespace();
|
||||
match src.peek_char() {
|
||||
Some('}') => {
|
||||
src.next_char();
|
||||
break;
|
||||
}
|
||||
Some(',') => {
|
||||
src.next_char();
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
ParsedType::Object(inner)
|
||||
}
|
||||
Some(_) => {
|
||||
let t = src.next_word().to_owned();
|
||||
src.skip_whitespace();
|
||||
@@ -131,6 +169,13 @@ pub fn type_from_parsed(
|
||||
.map(|v| type_from_parsed(v, info))
|
||||
.collect::<Result<_, _>>()?,
|
||||
)),
|
||||
ParsedType::Object(o) => Arc::new(data::object::ObjectT(
|
||||
o.iter()
|
||||
.map(|(s, v)| -> Result<_, CheckError> {
|
||||
Ok((s.clone(), type_from_parsed(v, info)?))
|
||||
})
|
||||
.collect::<Result<_, _>>()?,
|
||||
)),
|
||||
ParsedType::Type(name) => match info
|
||||
.scopes
|
||||
.iter()
|
||||
|
||||
Reference in New Issue
Block a user