Skip to content

Commit 869ff61

Browse files
committed
lab1: language
Signed-off-by: Runji Wang <[email protected]>
0 parents  commit 869ff61

File tree

7 files changed

+373
-0
lines changed

7 files changed

+373
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/target

Cargo.lock

+224
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "egg-sql-labs"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
egg = "0.9"

src/lib.rs

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use egg::{define_language, Id, Symbol};
2+
3+
mod value;
4+
5+
pub use value::*;
6+
7+
pub type RecExpr = egg::RecExpr<Expr>;
8+
9+
define_language! {
10+
pub enum Expr {
11+
// values
12+
Constant(Value), // null, true, 1, 'hello'
13+
Column(Symbol), // t.a, b, c
14+
15+
// utilities
16+
"list" = List(Box<[Id]>), // (list ...)
17+
18+
// unary operations
19+
"-" = Neg(Id),
20+
"not" = Not(Id),
21+
"isnull" = IsNull(Id),
22+
23+
// binary operations
24+
"+" = Add([Id; 2]),
25+
"-" = Sub([Id; 2]),
26+
"*" = Mul([Id; 2]),
27+
"/" = Div([Id; 2]),
28+
"=" = Eq([Id; 2]),
29+
"<>" = NotEq([Id; 2]),
30+
">" = Gt([Id; 2]),
31+
"<" = Lt([Id; 2]),
32+
">=" = GtEq([Id; 2]),
33+
"<=" = LtEq([Id; 2]),
34+
"and" = And([Id; 2]),
35+
"or" = Or([Id; 2]),
36+
"xor" = Xor([Id; 2]),
37+
}
38+
}

src/main.rs

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fn main() {
2+
println!("Hello, world!");
3+
}

src/value.rs

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
use std::{fmt::Display, str::FromStr};
2+
3+
/// SQL value.
4+
///
5+
/// # Display and Parse Format
6+
///
7+
/// - Null: `null`
8+
/// - Bool: `false`
9+
/// - Integer: `1`
10+
/// - String: `'string'`
11+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
12+
pub enum Value {
13+
Null,
14+
Bool(bool),
15+
Int(i32),
16+
String(String),
17+
}
18+
19+
impl Display for Value {
20+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21+
match self {
22+
Value::Null => write!(f, "null"),
23+
Value::Bool(b) => write!(f, "{b}"),
24+
Value::Int(i) => write!(f, "{i}"),
25+
Value::String(s) => write!(f, "'{s}'"),
26+
}
27+
}
28+
}
29+
30+
impl FromStr for Value {
31+
type Err = String;
32+
33+
fn from_str(s: &str) -> Result<Self, Self::Err> {
34+
if s == "null" {
35+
return Ok(Value::Null);
36+
} else if let Ok(i) = s.parse() {
37+
return Ok(Value::Bool(i));
38+
} else if let Ok(i) = s.parse() {
39+
return Ok(Value::Int(i));
40+
} else if s.starts_with('\'') && s.ends_with('\'') {
41+
return Ok(Value::String(s[1..s.len() - 1].to_string()));
42+
}
43+
Err(s.to_string())
44+
}
45+
}

tests/1_language.rs

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
use egg_sql_labs::{Expr, RecExpr, Value};
2+
3+
#[test]
4+
fn values() {
5+
assert_parse_value("null", Value::Null);
6+
assert_parse_value("true", Value::Bool(true));
7+
assert_parse_value("1", Value::Int(1));
8+
assert_parse_value("'string'", Value::String("string".into()));
9+
}
10+
11+
#[test]
12+
fn columns() {
13+
assert_parse_expr("a");
14+
assert_parse_expr("t.a");
15+
}
16+
17+
#[test]
18+
fn list() {
19+
assert_parse_expr("(list null 1 2)");
20+
}
21+
22+
#[test]
23+
fn operations() {
24+
assert_parse_expr("(isnull null)");
25+
assert_parse_expr("(- a)");
26+
assert_parse_expr("(+ a b)");
27+
assert_parse_expr("(- a b)");
28+
assert_parse_expr("(* a b)");
29+
assert_parse_expr("(/ a b)");
30+
assert_parse_expr("(= a b)");
31+
assert_parse_expr("(<> a b)");
32+
assert_parse_expr("(> a b)");
33+
assert_parse_expr("(< a b)");
34+
assert_parse_expr("(>= a b)");
35+
assert_parse_expr("(<= a b)");
36+
assert_parse_expr("(not a)");
37+
assert_parse_expr("(and a b)");
38+
assert_parse_expr("(or a b)");
39+
assert_parse_expr("(xor a b)");
40+
}
41+
42+
#[track_caller]
43+
fn assert_parse_value(expr: &str, value: Value) {
44+
assert_eq!(
45+
expr.parse::<RecExpr>().unwrap()[0.into()],
46+
Expr::Constant(value)
47+
);
48+
}
49+
50+
#[track_caller]
51+
fn assert_parse_expr(expr: &str) {
52+
assert_eq!(expr.parse::<RecExpr>().unwrap().to_string(), expr);
53+
}

0 commit comments

Comments
 (0)