Browse Source

Add checks to idents, vars, and var boundaries

main
raffitz 3 years ago
parent
commit
dc64500432
Signed by: raffitz
GPG Key ID: BB3596BD0A31252D
  1. 118
      src/astree.rs
  2. 20
      src/error.rs
  3. 131
      src/main.rs

118
src/astree.rs

@ -1,15 +1,5 @@ @@ -1,15 +1,5 @@
use std::collections::HashMap;
#[derive(Debug, PartialEq)]
pub enum Error {
UnrecognisedBinaryOperator,
UnrecognisedCondition,
UnrecognisedJunction,
MissingVarValue,
MissingIdentAssignment,
MissingVarMap,
MissingIdentMap,
}
use crate::error::Error;
use std::collections::{HashMap, HashSet};
#[derive(Debug, PartialEq)]
pub enum FunctionType {
@ -41,8 +31,8 @@ impl FunctionData { @@ -41,8 +31,8 @@ impl FunctionData {
pub fn eval(
&self,
idents: Option<&HashMap<String, Expression>>,
vars: Option<&HashMap<char, f64>>,
idents: &Option<&HashMap<String, Expression>>,
vars: &Option<&HashMap<char, f64>>,
) -> Result<f64, Error> {
let value = self.arg.eval(idents, vars)?;
@ -79,8 +69,8 @@ impl OperationData { @@ -79,8 +69,8 @@ impl OperationData {
pub fn eval(
&self,
idents: Option<&HashMap<String, Expression>>,
vars: Option<&HashMap<char, f64>>,
idents: &Option<&HashMap<String, Expression>>,
vars: &Option<&HashMap<char, f64>>,
) -> Result<f64, Error> {
let left = self.left.eval(idents, vars)?;
let right = self.right.eval(idents, vars)?;
@ -130,29 +120,97 @@ impl Expression { @@ -130,29 +120,97 @@ impl Expression {
pub fn eval(
&self,
idents: Option<&HashMap<String, Expression>>,
vars: Option<&HashMap<char, f64>>,
idents: &Option<&HashMap<String, Expression>>,
vars: &Option<&HashMap<char, f64>>,
) -> Result<f64, Error> {
match self {
Expression::Float(f) => Ok(*f),
Expression::Function(f) => f.eval(idents, vars),
Expression::Operation(o) => o.eval(idents, vars),
Expression::Var(c) => {
let value = vars
.ok_or::<Error>(Error::MissingVarMap)?
.get(c)
.ok_or::<Error>(Error::MissingVarValue)?;
let var_values = vars.as_ref().ok_or::<Error>(Error::MissingVarMap)?;
let value = var_values.get(c).ok_or::<Error>(Error::MissingVarValue)?;
Ok(*value)
}
Expression::Ident(s) => {
let referred = idents
.ok_or::<Error>(Error::MissingIdentMap)?
let ident_exps = idents.as_ref().ok_or::<Error>(Error::MissingIdentMap)?;
let referred = ident_exps
.get(s)
.ok_or::<Error>(Error::MissingIdentAssignment)?;
referred.eval(idents, vars)
}
}
}
pub fn var_dependencies(
&self,
idents: &Option<&HashMap<String, Expression>>,
) -> Result<HashSet<char>, Error> {
match self {
Expression::Float(_) => Ok(HashSet::new()),
Expression::Function(f) => f.arg.var_dependencies(idents),
Expression::Operation(o) => {
let left = o.left.var_dependencies(idents)?;
let right = o.right.var_dependencies(idents)?;
let mut result: HashSet<char> = HashSet::new();
for dep in left {
result.insert(dep);
}
for dep in right {
result.insert(dep);
}
Ok(result)
}
Expression::Var(c) => {
let mut result: HashSet<char> = HashSet::new();
result.insert(*c);
Ok(result)
}
Expression::Ident(s) => {
let ident_exps = idents.as_ref().ok_or::<Error>(Error::MissingIdentMap)?;
let referred = ident_exps
.get(s)
.ok_or::<Error>(Error::MissingIdentAssignment)?;
referred.var_dependencies(idents)
}
}
}
pub fn ident_dependencies(
&self,
idents: &Option<&HashMap<String, Expression>>,
) -> Result<HashSet<String>, Error> {
match self {
Expression::Float(_) => Ok(HashSet::new()),
Expression::Function(f) => f.arg.ident_dependencies(idents),
Expression::Operation(o) => {
let left = o.left.ident_dependencies(idents)?;
let right = o.right.ident_dependencies(idents)?;
let mut result: HashSet<String> = HashSet::new();
for dep in left {
result.insert(dep);
}
for dep in right {
result.insert(dep);
}
Ok(result)
}
Expression::Var(_) => Ok(HashSet::new()),
Expression::Ident(s) => {
let mut result: HashSet<String> = HashSet::new();
result.insert(s.to_owned());
let ident_exps = idents.as_ref().ok_or::<Error>(Error::MissingIdentMap)?;
let referred = ident_exps
.get(s)
.ok_or::<Error>(Error::MissingIdentAssignment)?;
let recursive = referred.ident_dependencies(idents)?;
for dep in recursive {
result.insert(dep);
}
Ok(result)
}
}
}
}
#[derive(Debug)]
@ -171,8 +229,8 @@ impl Condition { @@ -171,8 +229,8 @@ impl Condition {
pub fn eval(
&self,
idents: Option<&HashMap<String, Expression>>,
vars: Option<&HashMap<char, f64>>,
idents: &Option<&HashMap<String, Expression>>,
vars: &Option<&HashMap<char, f64>>,
) -> Result<bool, Error> {
let left_val = self.left.eval(idents, vars)?;
let right_val = self.right.eval(idents, vars)?;
@ -203,8 +261,8 @@ impl JunctionData { @@ -203,8 +261,8 @@ impl JunctionData {
pub fn eval(
&self,
idents: Option<&HashMap<String, Expression>>,
vars: Option<&HashMap<char, f64>>,
idents: &Option<&HashMap<String, Expression>>,
vars: &Option<&HashMap<char, f64>>,
) -> Result<bool, Error> {
let left_val = self.left.eval(idents, vars)?;
let right_val = self.right.eval(idents, vars)?;
@ -237,8 +295,8 @@ impl Junction { @@ -237,8 +295,8 @@ impl Junction {
pub fn eval(
&self,
idents: Option<&HashMap<String, Expression>>,
vars: Option<&HashMap<char, f64>>,
idents: &Option<&HashMap<String, Expression>>,
vars: &Option<&HashMap<char, f64>>,
) -> Result<bool, Error> {
match self {
Junction::Meta(meta) => meta.eval(idents, vars),

20
src/error.rs

@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
#[derive(Debug, PartialEq)]
pub enum Error {
ParserError,
UnrecognisedBinaryOperator,
UnrecognisedCondition,
UnrecognisedJunction,
MissingVarValue,
MissingIdentAssignment,
MissingVarMap,
MissingIdentMap,
IllegalVarInBoundary,
IllegarBoundedVar,
UnboundedVar,
}
impl From<()> for Error {
fn from(_: ()) -> Self {
Error::ParserError
}
}

131
src/main.rs

@ -1,10 +1,12 @@ @@ -1,10 +1,12 @@
use clap::{crate_authors, crate_description, crate_name, crate_version, App, Arg};
use logos::Logos;
use pomelo::pomelo;
use std::collections::HashMap;
use std::fs;
use std::io::{Error, ErrorKind, Read};
mod astree;
mod error;
macro_rules! scale_message {
($n:ident) => {
@ -23,17 +25,17 @@ fn io_error(err: Error, path: &str) -> String { @@ -23,17 +25,17 @@ fn io_error(err: Error, path: &str) -> String {
pomelo! {
%include {
use logos::{Lexer, Logos};
use crate::astree::{Condition, Expression, FunctionType, Junction, Error};
use crate::astree::{Condition, Expression, FunctionType, Junction};
use std::collections::HashMap;
#[derive(Debug)]
pub struct Limit{
var: char,
min: Expression,
max: Expression,
pub struct Boundary{
pub var: char,
pub min: Expression,
pub max: Expression,
}
impl Limit{
impl Boundary{
pub fn new(
l: Expression,
lcond: char,
@ -48,14 +50,14 @@ pomelo! { @@ -48,14 +50,14 @@ pomelo! {
if rcond == '<' || rcond == '≤'{
let min = l;
let max = r;
return Ok(Limit{var,min,max});
return Ok(Boundary{var,min,max});
}
return Err(());
}else if lcond == '>' || lcond == '≥'{
if rcond == '>' || rcond == '≥'{
let min = r;
let max = l;
return Ok(Limit{var,min,max});
return Ok(Boundary{var,min,max});
}
return Err(());
}
@ -63,9 +65,9 @@ pomelo! { @@ -63,9 +65,9 @@ pomelo! {
}
}
type Limits = (Limit,Limit,Limit);
type Boundaries = [Boundary; 3];
type Return = (Option<HashMap<String,Expression>>,Limits,Junction);
type Return = (Option<HashMap<String,Expression>>, Boundaries, Junction);
fn read_var(lex: &mut Lexer<Token>) -> Option<char> {
lex.slice().chars().next()
@ -174,16 +176,16 @@ pomelo! { @@ -174,16 +176,16 @@ pomelo! {
%left LineEnd;
%type input Return;
input ::= limits(L) metajuncture(J) { (None,L,J) }
input ::= LineEnd limits(L) metajuncture(J) { (None,L,J) }
input ::= assignments(A) limits(L) metajuncture(J) { (Some(A),L,J) }
input ::= LineEnd assignments(A) limits(L) metajuncture(J) { (Some(A),L,J) }
input ::= boundaries(L) metajuncture(J) { (None,L,J) }
input ::= LineEnd boundaries(L) metajuncture(J) { (None,L,J) }
input ::= assignments(A) boundaries(L) metajuncture(J) { (Some(A),L,J) }
input ::= LineEnd assignments(A) boundaries(L) metajuncture(J) { (Some(A),L,J) }
%type limit Limit;
limit ::= expr(L) Qualifier(F) Var(V) Qualifier(S) expr(R) { Limit::new(L,F,V,S,R)? }
%type boundary Boundary;
boundary ::= expr(L) Qualifier(F) Var(V) Qualifier(S) expr(R) { Boundary::new(L,F,V,S,R)? }
%type limits Limits;
limits ::= limit(A) LineEnd limit(B) LineEnd limit(C) LineEnd { (A,B,C) }
%type boundaries Boundaries;
boundaries ::= boundary(A) LineEnd boundary(B) LineEnd boundary(C) LineEnd { [A,B,C] }
%type assignment (String,Expression);
assignment ::= Assign Ident(S) expr(E) { (S,E) }
@ -192,12 +194,22 @@ pomelo! { @@ -192,12 +194,22 @@ pomelo! {
assignments ::= assignment(A) LineEnd {
let (k,v) = A;
let mut m = HashMap::new();
m.insert(k,v);
let ident_arg = Some(&m);
if v.ident_dependencies(&ident_arg).is_ok() {
m.insert(k,v);
}else{
eprintln!("Undefined reference in {}",k);
}
m
}
assignments ::= assignment(A) LineEnd assignments(mut M){
assignments ::= assignments(mut M) assignment(A) LineEnd {
let (k,v) = A;
M.insert(k,v);
let ident_arg = Some(&M);
if v.ident_dependencies(&ident_arg).is_ok() {
M.insert(k,v);
}else{
eprintln!("Undefined reference in {}",k);
}
M
}
%type quality Condition;
@ -226,7 +238,9 @@ pomelo! { @@ -226,7 +238,9 @@ pomelo! {
expr ::= Ident(S) { Expression::ident(S) }
}
fn main() -> Result<(), ()> {
fn main() -> Result<(), error::Error> {
use error::Error;
let matches = App::new(crate_name!())
.version(crate_version!())
.author(crate_authors!())
@ -266,7 +280,7 @@ fn main() -> Result<(), ()> { @@ -266,7 +280,7 @@ fn main() -> Result<(), ()> {
)
.get_matches();
//let scale = matches.value_of("scale").map(|s| s.parse::<i32>().unwrap());
let scale = matches.value_of("scale").map(|s| s.parse::<i32>().unwrap());
let mut object_description = fs::File::open(matches.value_of("FILE").unwrap()).unwrap();
@ -280,7 +294,7 @@ fn main() -> Result<(), ()> { @@ -280,7 +294,7 @@ fn main() -> Result<(), ()> {
let mut line_ends = false;
for token in lex {
println!("{:?}", token);
//println!("{:?}", token);
if token == parser::Token::LineEnd {
if line_ends {
continue;
@ -293,9 +307,74 @@ fn main() -> Result<(), ()> { @@ -293,9 +307,74 @@ fn main() -> Result<(), ()> {
p.parse(token)?;
}
let tree = p.end_of_input()?;
println!("\n{:?}", tree);
let (assigns, limits, tree) = p.end_of_input()?;
let idents = assigns.unwrap_or_default();
let ident_arg = Some(&idents);
//println!("\n{:?}", tree);
//println!("\nRead {} bytes, scale is {}", size, scale.unwrap_or(1));
let mut min_x: Option<i64> = None;
let mut max_x: Option<i64> = None;
let mut min_y: Option<i64> = None;
let mut max_y: Option<i64> = None;
let mut min_z: Option<i64> = None;
let mut max_z: Option<i64> = None;
let mut vars = HashMap::new();
vars.insert('s', scale.unwrap_or(1) as f64);
for limit in &limits {
for dep in limit.min.var_dependencies(&ident_arg)? {
if dep != 's' {
eprintln!("Boundaries can only refer to s, not {}", dep);
return Err(Error::IllegalVarInBoundary);
}
}
for dep in limit.max.var_dependencies(&ident_arg)? {
if dep != 's' {
eprintln!("Boundaries can only refer to s, not {}", dep);
return Err(Error::IllegalVarInBoundary);
}
}
let var_arg = Some(&vars);
let min = limit.min.eval(&ident_arg, &var_arg)?.floor() as i64;
let max = limit.max.eval(&ident_arg, &var_arg)?.ceil() as i64;
match limit.var {
'x' => {
min_x = Some(min);
max_x = Some(max);
}
'y' => {
min_y = Some(min);
max_y = Some(max);
}
'z' => {
min_z = Some(min);
max_z = Some(max);
}
c => {
eprintln!("Bounded variables are x,y,z only, not {}", c);
return Err(Error::IllegarBoundedVar);
}
}
}
let mut unbounded = false;
if min_x.is_none() || max_x.is_none() {
unbounded = true;
eprintln!("x is unbounded");
}
if min_y.is_none() || max_y.is_none() {
unbounded = true;
eprintln!("y is unbounded");
}
if min_z.is_none() || max_z.is_none() {
unbounded = true;
eprintln!("z is unbounded");
}
if unbounded {
return Err(Error::UnboundedVar);
}
}
Ok(())

Loading…
Cancel
Save