finish concept parser
This commit is contained in:
parent
7bd7c39002
commit
57803002fc
1 changed files with 100 additions and 9 deletions
109
src/expr/mod.rs
109
src/expr/mod.rs
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue