finish concept parser

This commit is contained in:
Alain Emilia Anna Zscheile 2024-07-23 12:58:07 +02:00
parent 7bd7c39002
commit 57803002fc

View file

@ -60,7 +60,7 @@ impl<L: Clone + Eq + Ord> Expr<L> {
pub struct System {
pub vs: Vec<Expr<Link>>,
pub mons: Vec<(Vec<Expr<()>>, Expr<Link>)>,
pub mons: Vec<(Box<[Expr<()>]>, Expr<Link>)>,
}
impl System {
@ -111,6 +111,15 @@ pub enum ParseError {
#[error("invalid argument count {1} for function '{0}'")]
InvalidArgCount(String, usize),
#[error("invalid line format")]
InvalidLineFormat,
#[error("invalid statement ID")]
InvalidStmtId,
#[error("unparsed trailing data")]
InvalidTrail,
#[error("unable to parse integer: {0}")]
Int(#[from] std::num::ParseIntError),
@ -166,6 +175,10 @@ impl ParseLink for Link {
fn parse_expr<L: Clone + ParseLink>(slb: &mut StrLexerBase<'_>) -> Result<Expr<L>, ParseError> {
slb.consume_select(|i| i.is_whitespace());
if let Some(x) = L::parse_link(slb)? {
return Ok(Expr::Link(x));
}
if slb.inp.starts_with(|i: char| i == '-' || i.is_ascii_digit()) {
// float
let mut new_slb = (*slb).clone();
@ -227,19 +240,25 @@ fn parse_expr<L: Clone + ParseLink>(slb: &mut StrLexerBase<'_>) -> Result<Expr<L
}
}
fn parse_expr_final<L: Clone + ParseLink>(slb: &mut StrLexerBase) -> Result<Expr<L>, ParseError> {
let x = parse_expr(slb)?;
if !slb.inp.is_empty() {
return Err(ParseError::InvalidTrail);
}
Ok(x)
}
/**
# Example
```
dims; 1
%vs
# u_t + 0.11 u_x = 0
0; -0.11 0_0_
%mons
# monitor @ 1 + sin(t) => u
0; sum(1.0, sin(.)); 0_
# monitor u @ 1 + sin(t)
0_; sum(1.0, sin(.))
```
# Syntax:
@ -250,11 +269,83 @@ Expressions can use functions:
* `sum(args...)`: sum of the arguments
* `prod(args...)`: product of the arguments
* `sin(expr)`, `cos(expr)`, `tan(expr)`, `atan(expr)`: trigonomic functions of a single argument
and atomics:
and atomar expressions:
* floating point constants
*
* links (`identnr_derivd1(_derivdn)*`)
Note that numbered lines need to be ordered by their id (first column if there is one).
**/
pub fn parse_system(s: &str) -> Result<System, ParseError> {
todo!();
pub fn parse_system(s: &str) -> Result<System, ((usize, usize), ParseError)> {
let mut ret = System {
vs: Vec::new(),
mons: Vec::new(),
};
#[derive(PartialEq)]
enum Mode {
Start,
Vs,
Mons,
}
let mut mode = Mode::Start;
for (lnr, line) in s.lines().enumerate() {
let line = line.trim();
if line.starts_with('#') || line.is_empty() {
continue;
}
if line == "%vs" {
mode = Mode::Vs;
} else if line == "%mons" {
mode = Mode::Mons;
} else if mode == Mode::Vs {
let parts = line.split(';').collect::<Vec<_>>();
let (offset, expr) = match &*parts {
[] => unreachable!(),
[x] => (0, x),
[x, y] => {
match x.parse::<usize>() {
Ok(xid) if xid == ret.vs.len() => {},
_ => return Err(((lnr, 0), ParseError::InvalidStmtId)),
}
(x.len() + 1, y)
}
_ => return Err(((lnr, 0), ParseError::InvalidLineFormat)),
};
ret.vs.push({
let mut slb = StrLexerBase { inp: expr, offset };
match parse_expr_final::<Link>(&mut slb) {
Ok(x) => x,
Err(e) => return Err(((lnr, slb.offset), e)),
}
});
} else if mode == Mode::Mons {
let parts = line.split(';').collect::<Vec<_>>();
if parts.len() < 2 {
return Err(((lnr, 0), ParseError::InvalidLineFormat));
}
let mut slb = StrLexerBase { inp: parts[0], offset: 0 };
let valxp = match parse_expr_final::<Link>(&mut slb) {
Ok(x) => x,
Err(e) => return Err(((lnr, slb.offset), e)),
};
let mut location = Vec::with_capacity(parts.len() - 1);
for i in &parts[1..] {
slb.offset += 1;
slb.inp = i;
let lxp = match parse_expr_final::<()>(&mut slb) {
Ok(x) => x,
Err(e) => return Err(((lnr, slb.offset), e)),
};
location.push(lxp);
}
ret.mons.push((location.into_boxed_slice(), valxp));
}
}
Ok(ret)
}