From b16a4eefe4d2a0e38ab15f03f83a7a35ff5334a0 Mon Sep 17 00:00:00 2001 From: Martin Berg Alstad Date: Fri, 7 Jun 2024 16:27:52 +0200 Subject: [PATCH] Replaced binary tuple with struct --- spec/main.tsp | 54 +++++++--------- spec/models.tsp | 31 ++++++++++ .../@typespec/openapi3/openapi.yaml | 61 ++++++++++++++----- src/expressions/expression.rs | 12 ++-- src/expressions/helpers.rs | 10 +-- src/expressions/simplify.rs | 40 ++++++------ src/main.rs | 2 +- 7 files changed, 129 insertions(+), 81 deletions(-) create mode 100644 spec/models.tsp diff --git a/spec/main.tsp b/spec/main.tsp index 602d143..2bafe4a 100644 --- a/spec/main.tsp +++ b/spec/main.tsp @@ -1,39 +1,27 @@ -import "@typespec/openapi3"; -using TypeSpec.OpenAPI; +import "@typespec/http"; +import "./models.tsp"; +using TypeSpec.Http; +using Models; -enum BinaryOperator { - AND, - OR, - IMPLICATION -} - -model ExpressionNot { - not: Expression; -} - -// TODO tuple type, possible in OpenAPI 3.1, but unsupported in typespec -model ExpressionBinary { - operator: BinaryOperator; - left: Expression; - right: Expression; -} - -model ExpressionAtomic { - atomic: string; -} - -@oneOf -union Expression { - ExpressionNot; - ExpressionBinary; - ExpressionAtomic; -} - -model SimplifyResponse { +@service({ + title: "Simplify Truth Expressions", +}) +namespace Simplify { + model SimplifyResponse { before: string; after: string; - orderOfOperations: string[]; + orderOfOperations?: string[] = []; expression: Expression; } -op simplify(): SimplifyResponse; +model SimplifyOptions { + lang: "en" | "nb" = "en"; + simplify: boolean = true; + caseSensitive: boolean = false; +} + +op simplify( + @path exp: string, + @query query?: SimplifyOptions +): SimplifyResponse; +} diff --git a/spec/models.tsp b/spec/models.tsp new file mode 100644 index 0000000..7fbdba0 --- /dev/null +++ b/spec/models.tsp @@ -0,0 +1,31 @@ +import "@typespec/openapi3"; +using TypeSpec.OpenAPI; + +namespace Models; + +enum BinaryOperator { + AND, + OR, + IMPLICATION +} + +model ExpressionNot { + not: Expression; +} + +model ExpressionBinary { + left: Expression; + operator: BinaryOperator; + right: Expression; +} + +model ExpressionAtomic { + atomic: string; +} + +@oneOf +union Expression { + ExpressionNot; + ExpressionBinary; + ExpressionAtomic; +} \ No newline at end of file diff --git a/spec/tsp-output/@typespec/openapi3/openapi.yaml b/spec/tsp-output/@typespec/openapi3/openapi.yaml index e7ae80c..7b878e1 100644 --- a/spec/tsp-output/@typespec/openapi3/openapi.yaml +++ b/spec/tsp-output/@typespec/openapi3/openapi.yaml @@ -1,13 +1,23 @@ openapi: 3.0.0 info: - title: (title) + title: Simplify Truth Expressions version: 0.0.0 tags: [] paths: - /: + /{exp}: get: operationId: simplify - parameters: [] + parameters: + - name: exp + in: path + required: true + schema: + type: string + - name: query + in: query + required: false + schema: + $ref: '#/components/schemas/SimplifyOptions' responses: '200': description: The request has succeeded. @@ -17,50 +27,68 @@ paths: $ref: '#/components/schemas/SimplifyResponse' components: schemas: - BinaryOperator: + Expression: + oneOf: + - $ref: '#/components/schemas/Models.ExpressionNot' + - $ref: '#/components/schemas/Models.ExpressionBinary' + - $ref: '#/components/schemas/Models.ExpressionAtomic' + Models.BinaryOperator: type: string enum: - AND - OR - IMPLICATION - Expression: - oneOf: - - $ref: '#/components/schemas/ExpressionNot' - - $ref: '#/components/schemas/ExpressionBinary' - - $ref: '#/components/schemas/ExpressionAtomic' - ExpressionAtomic: + Models.ExpressionAtomic: type: object required: - atomic properties: atomic: type: string - ExpressionBinary: + Models.ExpressionBinary: type: object required: - - operator - left + - operator - right properties: - operator: - $ref: '#/components/schemas/BinaryOperator' left: $ref: '#/components/schemas/Expression' + operator: + $ref: '#/components/schemas/Models.BinaryOperator' right: $ref: '#/components/schemas/Expression' - ExpressionNot: + Models.ExpressionNot: type: object required: - not properties: not: $ref: '#/components/schemas/Expression' + SimplifyOptions: + type: object + required: + - lang + - simplify + - caseSensitive + properties: + lang: + type: string + enum: + - en + - nb + default: en + simplify: + type: boolean + default: true + caseSensitive: + type: boolean + default: false SimplifyResponse: type: object required: - before - after - - orderOfOperations - expression properties: before: @@ -71,5 +99,6 @@ components: type: array items: type: string + default: [] expression: $ref: '#/components/schemas/Expression' diff --git a/src/expressions/expression.rs b/src/expressions/expression.rs index 57e3e84..b6df8b3 100644 --- a/src/expressions/expression.rs +++ b/src/expressions/expression.rs @@ -12,7 +12,7 @@ pub trait OppositeEq { #[serde(rename_all = "camelCase")] pub enum Expression { Not(Box), - Binary(Box, BinaryOperator, Box), + Binary { left: Box, operator: BinaryOperator, right: Box }, Atomic(String), } @@ -20,7 +20,7 @@ impl Expression { pub fn is_atomic(&self) -> bool { match self { Expression::Not(expr) => expr.is_atomic(), - Expression::Binary(_, _, _) => false, + Expression::Binary { .. } => false, Expression::Atomic(_) => true } } @@ -32,7 +32,7 @@ impl Expression { pub fn exists(&self, atomic_value: &str) -> bool { match self { Expression::Not(expr) => expr.exists(atomic_value), - Expression::Binary(left, _, right) => left.exists(atomic_value) || right.exists(atomic_value), + Expression::Binary { left, right, .. } => left.exists(atomic_value) || right.exists(atomic_value), Expression::Atomic(value) => value == atomic_value, } } @@ -69,14 +69,14 @@ impl Display for Expression { match self { Expression::Not(expr) if expr.is_atomic() => write!(f, "¬{expr}"), Expression::Not(expr) => write!(f, "¬({expr})"), - Expression::Binary(left, BinaryOperator::And, right) => { + Expression::Binary { left, operator: BinaryOperator::And, right } => { write!(f, "{left} ⋀ {right}") } // TODO do not use parentheses on root level or if several operators are on the same level - Expression::Binary(left, BinaryOperator::Or, right) => { + Expression::Binary { left, operator: BinaryOperator::Or, right } => { write!(f, "({left} ⋁ {right})") } - Expression::Binary(left, BinaryOperator::Implication, right) => { + Expression::Binary { left, operator: BinaryOperator::Implication, right } => { write!(f, "{left} ➔ {right}") } Expression::Atomic(value) => write!(f, "{value}"), diff --git a/src/expressions/helpers.rs b/src/expressions/helpers.rs index e794146..c8f6e87 100644 --- a/src/expressions/helpers.rs +++ b/src/expressions/helpers.rs @@ -21,8 +21,8 @@ macro_rules! implies { #[macro_export] macro_rules! binary { - ($left:expr, $op:expr, $right:expr) => { - $crate::expressions::expression::Expression::Binary(Box::new($left), $op, Box::new($right)) + ($left:expr, $operator:expr, $right:expr) => { + $crate::expressions::expression::Expression::Binary { left: Box::new($left), operator: $operator, right: Box::new($right) } }; } @@ -78,16 +78,16 @@ mod tests { #[test] fn eval_and() { - assert_eq!(eval!("a" && "b"), Binary(Box::new(Atomic("a".to_string())), And, Box::new(Atomic("b".to_string())))); + assert_eq!(eval!("a" && "b"), Binary { left: Box::new(Atomic("a".to_string())), operator: And, right: Box::new(Atomic("b".to_string())) }); } #[test] fn eval_or() { - assert_eq!(eval!("a" || "b"), Binary(Box::new(Atomic("a".to_string())), Or, Box::new(Atomic("b".to_string())))); + assert_eq!(eval!("a" || "b"), Binary { left: Box::new(Atomic("a".to_string())), operator: Or, right: Box::new(Atomic("b".to_string())) }); } #[test] fn eval_implies() { - assert_eq!(eval!("a" => "b"), Binary(Box::new(Atomic("a".to_string())), Implication, Box::new(Atomic("b".to_string())))); + assert_eq!(eval!("a" => "b"), Binary { left: Box::new(Atomic("a".to_string())), operator: Implication, right: Box::new(Atomic("b".to_string())) }); } } diff --git a/src/expressions/simplify.rs b/src/expressions/simplify.rs index 1385f90..b93f5ec 100644 --- a/src/expressions/simplify.rs +++ b/src/expressions/simplify.rs @@ -28,12 +28,12 @@ impl Simplify for Expression { fn elimination_of_implication(&self) -> Self { match self { Expression::Not(expr) => not!(expr.elimination_of_implication()), - Expression::Binary(left, BinaryOperator::Implication, right) => { + Expression::Binary { left, operator: BinaryOperator::Implication, right } => { let left = left.elimination_of_implication(); let right = right.elimination_of_implication(); or!(not!(left), right) } - Expression::Binary(left, operator, right) => { + Expression::Binary { left, operator, right } => { let left = left.elimination_of_implication(); let right = right.elimination_of_implication(); binary!(left, *operator, right) @@ -54,7 +54,7 @@ impl Simplify for Expression { not!(expr.double_negation_elimination()) } } - Expression::Binary(left, operator, right) => { + Expression::Binary { left, operator, right } => { let left = left.double_negation_elimination(); let right = right.double_negation_elimination(); binary!(left, *operator, right) @@ -67,13 +67,13 @@ impl Simplify for Expression { match self { Expression::Not(expr) => { match *expr.clone() { - Expression::Binary(left, BinaryOperator::And, right) => { + Expression::Binary { left, operator: BinaryOperator::And, right } => { // TODO unnecessary cloning calls to de_morgans_laws? let left = not!(left.de_morgans_laws()); let right = not!(right.de_morgans_laws()); or!(left, right).de_morgans_laws() } - Expression::Binary(left, BinaryOperator::Or, right) => { + Expression::Binary { left, operator: BinaryOperator::Or, right } => { let left = not!(left.de_morgans_laws()); let right = not!(right.de_morgans_laws()); and!(left, right).de_morgans_laws() @@ -81,7 +81,7 @@ impl Simplify for Expression { _ => not!(expr.de_morgans_laws()), } } - Expression::Binary(left, operator, right) => { + Expression::Binary { left, operator, right } => { let left = left.de_morgans_laws(); let right = right.de_morgans_laws(); binary!(left, *operator, right) @@ -93,10 +93,10 @@ impl Simplify for Expression { // TODO deduplicate code fn absorption_law(&self) -> Self { match self { - Expression::Binary(left, BinaryOperator::And, right) => { + Expression::Binary { left, operator: BinaryOperator::And, right } => { let (left_ref, right_ref) = (left.as_ref(), right.as_ref()); match (left_ref, right_ref) { - (_, Expression::Binary(right_left, BinaryOperator::Or, right_right)) => { + (_, Expression::Binary { left: right_left, operator: BinaryOperator::Or, right: right_right }) => { if left_ref == right_left.as_ref() || left_ref == right_right.as_ref() { return left.absorption_law(); } else if right_left.is_atomic() && right_right.is_atomic() && left.opposite_eq(right_left) { @@ -108,7 +108,7 @@ impl Simplify for Expression { } and!(left.absorption_law(), right.absorption_law()) } - (Expression::Binary(left_left, BinaryOperator::Or, left_right), _) => { + (Expression::Binary { left: left_left, operator: BinaryOperator::Or, right: left_right }, _) => { if right_ref == left_left.as_ref() || right_ref == left_right.as_ref() { return right.absorption_law(); } else if left_left.is_atomic() && left_right.is_atomic() && right.opposite_eq(left_left) { @@ -123,10 +123,10 @@ impl Simplify for Expression { (left, right) => and!(left.absorption_law(), right.absorption_law()) } } - Expression::Binary(left, BinaryOperator::Or, right) => { + Expression::Binary { left, operator: BinaryOperator::Or, right } => { let (left_ref, right_ref) = (left.as_ref(), right.as_ref()); match (left_ref, right_ref) { - (_, Expression::Binary(right_left, BinaryOperator::And, right_right)) => { + (_, Expression::Binary { left: right_left, operator: BinaryOperator::And, right: right_right }) => { if left_ref == right_left.as_ref() || left_ref == right_right.as_ref() { return left.absorption_law(); } else if right_left.is_atomic() && right_right.is_atomic() && left.opposite_eq(right_left) { @@ -138,7 +138,7 @@ impl Simplify for Expression { } or!(left.absorption_law(), right.absorption_law()) } - (Expression::Binary(left_left, BinaryOperator::And, left_right), _) => { + (Expression::Binary { left: left_left, operator: BinaryOperator::And, right: left_right }, _) => { if right_ref == left_left.as_ref() || right_ref == left_right.as_ref() { return right.absorption_law(); } else if left_left.is_atomic() && left_right.is_atomic() && right.opposite_eq(left_left) { @@ -153,7 +153,7 @@ impl Simplify for Expression { (left, right) => or!(left.absorption_law(), right.absorption_law()) } } - Expression::Binary(left, operator, right) => { + Expression::Binary { left, operator, right } => { let left = left.absorption_law(); let right = right.absorption_law(); binary!(left, *operator, right) @@ -170,14 +170,14 @@ impl Simplify for Expression { // TODO deduplicate code fn distribution_law(&self) -> Self { match self { - Expression::Binary(left, BinaryOperator::And, right) => { + Expression::Binary { left, operator: BinaryOperator::And, right } => { match (left.as_ref(), right.as_ref()) { - (Expression::Atomic(_), Expression::Binary(right_left, BinaryOperator::Or, right_right)) => { + (Expression::Atomic(_), Expression::Binary { left: right_left, operator: BinaryOperator::Or, right: right_right }) => { let right_left = right_left.distribution_law(); let right_right = right_right.distribution_law(); or!(and!(*left.clone(), right_left), and!(*left.clone(), right_right)) } - (Expression::Binary(left_left, BinaryOperator::Or, left_right), Expression::Atomic(_)) => { + (Expression::Binary { left: left_left, operator: BinaryOperator::Or, right: left_right }, Expression::Atomic(_)) => { let left_left = left_left.distribution_law(); let left_right = left_right.distribution_law(); or!(and!(left_left, *right.clone()), and!(left_right, *right.clone())) @@ -185,14 +185,14 @@ impl Simplify for Expression { (left, right) => and!(left.distribution_law(), right.distribution_law()) } } - Expression::Binary(left, BinaryOperator::Or, right) => { + Expression::Binary { left, operator: BinaryOperator::Or, right } => { match (left.as_ref(), right.as_ref()) { - (Expression::Atomic(_), Expression::Binary(right_left, BinaryOperator::And, right_right)) => { + (Expression::Atomic(_), Expression::Binary { left: right_left, operator: BinaryOperator::And, right: right_right }) => { let right_left = right_left.distribution_law(); let right_right = right_right.distribution_law(); and!(or!(*left.clone(), right_left), or!(*left.clone(), right_right)) } - (Expression::Binary(left_left, BinaryOperator::And, left_right), Expression::Atomic(_)) => { + (Expression::Binary { left: left_left, operator: BinaryOperator::And, right: left_right }, Expression::Atomic(_)) => { let left_left = left_left.distribution_law(); let left_right = left_right.distribution_law(); and!(or!(left_left, *right.clone()), or!(left_right, *right.clone())) @@ -200,7 +200,7 @@ impl Simplify for Expression { (left, right) => or!(left.distribution_law(), right.distribution_law()) } } - Expression::Binary(left, operator, right) => { + Expression::Binary { left, operator, right } => { let left = left.distribution_law(); let right = right.distribution_law(); binary!(left, *operator, right) diff --git a/src/main.rs b/src/main.rs index d951783..befb31d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ use std::net::SocketAddr; -use tokio::net::{TcpListener, ToSocketAddrs}; +use tokio::net::TcpListener; use crate::routing::{simplify, table};