Replaced binary tuple with struct

This commit is contained in:
Martin Berg Alstad 2024-06-07 16:27:52 +02:00
parent 4fe388aca3
commit b16a4eefe4
7 changed files with 129 additions and 81 deletions

View File

@ -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;
}

31
spec/models.tsp Normal file
View File

@ -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;
}

View File

@ -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'

View File

@ -12,7 +12,7 @@ pub trait OppositeEq {
#[serde(rename_all = "camelCase")]
pub enum Expression {
Not(Box<Expression>),
Binary(Box<Expression>, BinaryOperator, Box<Expression>),
Binary { left: Box<Expression>, operator: BinaryOperator, right: Box<Expression> },
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}"),

View File

@ -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())) });
}
}

View File

@ -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)

View File

@ -1,6 +1,6 @@
use std::net::SocketAddr;
use tokio::net::{TcpListener, ToSocketAddrs};
use tokio::net::TcpListener;
use crate::routing::{simplify, table};