### Example Test Structure in Rust Source: https://github.com/bl1nk-bot/poe-sdk-rs/blob/main/CONTRIBUTING.md Demonstrates a basic test structure using Rust's built-in testing framework. Includes setup, action, and assertion phases for testing functionality and error handling. ```rust #[cfg(test)] mod tests { use super::*; #[test] fn test_basic_functionality() { // Arrange let input = 42; let expected = 84; // Act let result = example_function(input); // Assert assert_eq!(result, expected); } #[test] fn test_error_cases() { // Test error handling let result = example_function(-1); assert!(result.is_err()); } } ``` -------------------------------- ### Install Formula Engine Source: https://context7.com/bl1nk-bot/poe-sdk-rs/llms.txt Add the formula_engine dependency to your Cargo.toml file to use the library. ```toml [dependencies] formula_engine = "0.1.0" ``` -------------------------------- ### Date Functions in Formula Engine Source: https://github.com/bl1nk-bot/poe-sdk-rs/blob/main/README.md Examples of date and time manipulation functions, including getting the current time, adding days, calculating differences, and extracting date parts. ```plaintext now() → `"2023-12-01T12:00:00Z"` ``` ```plaintext date_add("2023-01-01", 5) → `"2023-01-06T00:00:00Z"` ``` ```plaintext date_diff("2023-01-05", "2023-01-01") → `4` ``` ```plaintext year("2023-05-15") → `2023` ``` ```plaintext month("2023-05-15") → `5` ``` ```plaintext day("2023-05-15") → `15` ``` -------------------------------- ### Handle Parsing Errors (`ParseError`) Source: https://context7.com/bl1nk-bot/poe-sdk-rs/llms.txt Shows how to catch a `ParseError` (E002) that arises from incorrect syntax during the parsing phase. This example uses tokens that represent an incomplete expression. ```rust use formula_engine::{tokenize, parse, evaluate, Context, FunctionRegistry}; use formula_engine::error::{ErrorKind, FormulaError}; use formula_engine::builtins; let mut reg = FunctionRegistry::new(); builtins::register_all(&mut reg); let ctx = Context::new(); // E002 - ParseError: syntax ผิด let tokens = tokenize("1 + (2").unwrap(); let err = parse(&tokens).unwrap_err(); assert_eq!(err.kind, ErrorKind::ParseError); assert_eq!(err.code, "E002"); ``` -------------------------------- ### String Functions in Formula Engine Source: https://github.com/bl1nk-bot/poe-sdk-rs/blob/main/README.md Provides examples of string manipulation functions available in the formula engine, such as length, case conversion, and substring checks. ```plaintext len("hello") → `5` ``` ```plaintext upper("abc") → `"ABC"` ``` ```plaintext lower("ABC") → `"abc"` ``` ```plaintext contains("hello", "ell") → `true` ``` ```plaintext starts_with("hello", "he") → `true` ``` ```plaintext ends_with("hello", "lo") → `true` ``` -------------------------------- ### Handle Empty Collection Errors (`FunctionError` E011) Source: https://context7.com/bl1nk-bot/poe-sdk-rs/llms.txt Illustrates catching a `FunctionError` (E011) when a function like `avg` is called with an empty collection. This example attempts to calculate the average of an empty array. ```rust use formula_engine::{tokenize, parse, evaluate, Context, FunctionRegistry}; use formula_engine::error::{ErrorKind, FormulaError}; use formula_engine::builtins; let mut reg = FunctionRegistry::new(); builtins::register_all(&mut reg); let ctx = Context::new(); // E011 - FunctionError: collection ว่าง let tokens = tokenize("avg([])").unwrap(); let ast = parse(&tokens).unwrap(); let err = evaluate(&ast, &ctx, ®).unwrap_err(); assert_eq!(err.code, "E011"); ``` -------------------------------- ### Handle Incorrect Function Argument Count Errors (`FunctionError` E008) Source: https://context7.com/bl1nk-bot/poe-sdk-rs/llms.txt Shows how to catch a `FunctionError` (E008) related to an incorrect number of arguments passed to a function. This example calls the `len` function with two arguments instead of the expected one. ```rust use formula_engine::{tokenize, parse, evaluate, Context, FunctionRegistry}; use formula_engine::error::{ErrorKind, FormulaError}; use formula_engine::builtins; let mut reg = FunctionRegistry::new(); builtins::register_all(&mut reg); let ctx = Context::new(); // E008 - FunctionError: จำนวน argument ไม่ตรง let tokens = tokenize("len("a", "b")").unwrap(); let ast = parse(&tokens).unwrap(); let err = evaluate(&ast, &ctx, ®).unwrap_err(); assert_eq!(err.code, "E008"); ``` -------------------------------- ### Build and Run Poe Extension Source: https://github.com/bl1nk-bot/poe-sdk-rs/blob/main/docs/idea-extension-poe.md Build the Rust extension in release mode and then execute the compiled binary. This is the command to run the extension after compilation. ```bash cargo build --release ./target/release/poe_extension ``` -------------------------------- ### Run Doc-Tests in Poe SDK Source: https://github.com/bl1nk-bot/poe-sdk-rs/blob/main/README.md Command to run documentation tests (doc-tests) in the Poe SDK project. ```bash cargo test --doc ``` -------------------------------- ### Run All Tests in Poe SDK Source: https://github.com/bl1nk-bot/poe-sdk-rs/blob/main/README.md Command to execute all tests within the Poe SDK project. ```bash cargo test ``` -------------------------------- ### Demonstrate `Value` Enum Variants and Comparisons Source: https://context7.com/bl1nk-bot/poe-sdk-rs/llms.txt Illustrates the different variants of the `Value` enum, including Number, String, Bool, Null, Array, and Map. Shows how to create instances of each type and perform equality comparisons. ```rust use formula_engine::Value; use std::collections::HashMap; // Number: ตัวเลข f64 let n = Value::Number(42.0); let pi = Value::Number(3.14159); let neg = Value::Number(-7.5); // String: ข้อความ UTF-8 let s = Value::String("สวัสดีโลก".to_string()); let empty = Value::String(String::new()); // Bool: ค่าความจริง let t = Value::Bool(true); let f = Value::Bool(false); // Null: ค่าว่าง let null = Value::Null; // Array: อาร์เรย์แบบ heterogeneous let arr = Value::Array(vec![ Value::Number(1.0), Value::String("hello".to_string()), Value::Bool(true), Value::Null, ]); // Array ซ้อนกัน let matrix = Value::Array(vec![ Value::Array(vec![Value::Number(1.0), Value::Number(2.0)]), Value::Array(vec![Value::Number(3.0), Value::Number(4.0)]), ]); // Map: dictionary ที่มี key เป็น String let mut person = HashMap::new(); person.insert("name".to_string(), Value::String("Alice".to_string())); person.insert("age".to_string(), Value::Number(30.0)); person.insert("active".to_string(), Value::Bool(true)); let map_val = Value::Map(person); // เปรียบเทียบค่า assert_eq!(Value::Number(42.0), Value::Number(42.0)); assert_ne!(Value::Number(1.0), Value::Number(2.0)); assert_eq!( Value::Array(vec![Value::Number(1.0)]), Value::Array(vec![Value::Number(1.0)]) ); ``` -------------------------------- ### Run Specific Module Tests in Poe SDK Source: https://github.com/bl1nk-bot/poe-sdk-rs/blob/main/README.md Commands to run tests for specific modules like lexer, parser, or eval within the Poe SDK. ```bash cargo test lexer ``` ```bash cargo test parser ``` ```bash cargo test eval ``` -------------------------------- ### Formula Engine Operators and Precedence Source: https://context7.com/bl1nk-bot/poe-sdk-rs/llms.txt Demonstrates the use of various operators including arithmetic, string concatenation, comparison, and logical operators. Ensures correct operator precedence is handled. ```rust use formula_engine::{tokenize, parse, evaluate, Context, FunctionRegistry, Value}; use formula_engine::builtins; let mut reg = FunctionRegistry::new(); builtins::register_all(&mut reg); let ctx = Context::new(); let eval = |f: &str| { evaluate(&parse(&tokenize(f).unwrap()).unwrap(), &ctx, ®).unwrap() }; // คณิตศาสตร์ (operator precedence) assert_eq!(eval("1 + 2 * 3"), Value::Number(7.0)); // 1 + (2*3) assert_eq!(eval("(1 + 2) * 3"), Value::Number(9.0)); // (1+2) * 3 assert_eq!(eval("10 - 4 / 2"), Value::Number(8.0)); // 10 - (4/2) assert_eq!(eval("-5 + 3"), Value::Number(-2.0)); // unary minus // ต่อข้อความด้วย + assert_eq!(eval("\"hello\" + \" \" + \"world\""), Value::String("hello world".to_string())); // เปรียบเทียบ (คืน Bool เสมอ) assert_eq!(eval("5 > 3"), Value::Bool(true)); assert_eq!(eval("3 >= 3"), Value::Bool(true)); assert_eq!(eval("2 < 1"), Value::Bool(false)); assert_eq!(eval("1 <= 2"), Value::Bool(true)); assert_eq!(eval("5 == 5"), Value::Bool(true)); assert_eq!(eval("5 != 3"), Value::Bool(true)); // ตรรกะ assert_eq!(eval("true && false"), Value::Bool(false)); assert_eq!(eval("true || false"), Value::Bool(true)); assert_eq!(eval("!true"), Value::Bool(false)); assert_eq!(eval("!false && true"), Value::Bool(true)); // ลำดับความสำคัญ: && มีลำดับสูงกว่า || assert_eq!(eval("true || false && false"), Value::Bool(true)); // true || (false && false) assert_eq!(eval("5 > 3 && 2 == 2"), Value::Bool(true)); ``` -------------------------------- ### Collection Functions in Formula Engine Source: https://github.com/bl1nk-bot/poe-sdk-rs/blob/main/README.md Illustrates functions for operating on collections (arrays), including sum, average, min, max, count, and join. ```plaintext sum([1, 2, 3]) → `6` ``` ```plaintext avg([1, 2, 3]) → `2` ``` ```plaintext min([1, 2, 3]) → `1` ``` ```plaintext max([1, 2, 3]) → `3` ``` ```plaintext count([1, 2, 3]) → `3` ``` ```plaintext join(["a","b"], ",") → `"a,b"` ``` -------------------------------- ### Handle Context Errors (`ContextError`) Source: https://context7.com/bl1nk-bot/poe-sdk-rs/llms.txt Demonstrates catching a `ContextError` (E005) when a variable used in an expression is not found in the provided context. It also shows how to print the error message. ```rust use formula_engine::{tokenize, parse, evaluate, Context, FunctionRegistry}; use formula_engine::error::{ErrorKind, FormulaError}; use formula_engine::builtins; let mut reg = FunctionRegistry::new(); builtins::register_all(&mut reg); let ctx = Context::new(); // E005 - ContextError: ตัวแปรไม่มีใน context let tokens = tokenize("noVar + 1").unwrap(); let ast = parse(&tokens).unwrap(); let err = evaluate(&ast, &ctx, ®).unwrap_err(); assert_eq!(err.kind, ErrorKind::ContextError); assert_eq!(err.code, "E005"); println!("ข้อผิดพลาด: {}", err); // แสดง "[E005] ไม่พบตัวแปร 'noVar'" ``` -------------------------------- ### Operators and Precedence Source: https://context7.com/bl1nk-bot/poe-sdk-rs/llms.txt Details the operators supported by the Formula Engine, including their behavior with different data types and their order of operations. ```APIDOC ## Operators (Operators) and Precedence ### Description The Formula Engine supports a full set of operators with correct precedence. The `+` operator works for both Numbers (addition) and Strings (concatenation), but mixing types is not allowed. Comparison operators always return a Boolean. ### Supported Operators - **Arithmetic:** `+`, `-`, `*`, `/` - **Comparison:** `>`, `>=`, `<`, `<=`, `==`, `!=` - **Logical:** `&&` (AND), `||` (OR), `!` (NOT) ### Operator Precedence - `!` (highest) - `*`, `/` - `+`, `-` - `>`, `>=`, `<`, `<=`, `==`, `!=` - `&&` - `||` (lowest) Parentheses `()` can be used to override precedence. ### Example Usage ```rust use formula_engine::{tokenize, parse, evaluate, Context, FunctionRegistry, Value}; use formula_engine::builtins; let mut reg = FunctionRegistry::new(); builtins::register_all(&mut reg); let ctx = Context::new(); let eval = |f: &str| { evaluate(&parse(&tokenize(f).unwrap()).unwrap(), &ctx, ®).unwrap() }; // Mathematical operations assert_eq!(eval("1 + 2 * 3"), Value::Number(7.0)); // 1 + (2*3) assert_eq!(eval("(1 + 2) * 3"), Value::Number(9.0)); // (1+2) * 3 assert_eq!(eval("10 - 4 / 2"), Value::Number(8.0)); // 10 - (4/2) assert_eq!(eval("-5 + 3"), Value::Number(-2.0)); // unary minus // String concatenation assert_eq!(eval("\"hello\" + \" \" + \"world\" "), Value::String("hello world".to_string())); // Comparison (always returns Bool) assert_eq!(eval("5 > 3"), Value::Bool(true)); assert_eq!(eval("3 >= 3"), Value::Bool(true)); assert_eq!(eval("2 < 1"), Value::Bool(false)); assert_eq!(eval("1 <= 2"), Value::Bool(true)); assert_eq!(eval("5 == 5"), Value::Bool(true)); assert_eq!(eval("5 != 3"), Value::Bool(true)); // Logical operations assert_eq!(eval("true && false"), Value::Bool(false)); assert_eq!(eval("true || false"), Value::Bool(true)); assert_eq!(eval("!true"), Value::Bool(false)); assert_eq!(eval("!false && true"), Value::Bool(true)); // Precedence example: && has higher precedence than || assert_eq!(eval("true || false && false"), Value::Bool(true)); // true || (false && false) assert_eq!(eval("5 > 3 && 2 == 2"), Value::Bool(true)); ``` ``` -------------------------------- ### Math Functions in Formula Engine Source: https://github.com/bl1nk-bot/poe-sdk-rs/blob/main/README.md Demonstrates mathematical functions including absolute value, minimum, and maximum of two numbers. ```plaintext abs(-5) → `5` ``` ```plaintext min(3, 1) → `1` ``` ```plaintext max(3, 1) → `3` ``` -------------------------------- ### Date and Time Functions Source: https://context7.com/bl1nk-bot/poe-sdk-rs/llms.txt Functions for date and time manipulation using ISO 8601 format. `now()` returns the current UTC timestamp. Functions include creating dates, adding days, calculating differences, and extracting year, month, or day. ```rust use formula_engine::{tokenize, parse, evaluate, Context, FunctionRegistry, Value}; use formula_engine::builtins; let mut reg = FunctionRegistry::new(); builtins::register_all(&mut reg); let ctx = Context::new(); let eval = |f: &str| { evaluate(&parse(&tokenize(f).unwrap()).unwrap(), &ctx, ®).unwrap() }; // date(year, month, day) → "YYYY-MM-DD" assert_eq!(eval("date(2025, 6, 15)"), Value::String("2025-06-15".to_string())); // date_add(date_str, days) → เพิ่มจำนวนวัน assert_eq!(eval("date_add(\"2023-01-01\", 10)"), Value::String("2023-01-11".to_string())); assert_eq!(eval("date_add(\"2023-01-25\", 10)"), Value::String("2023-02-04".to_string())); // date_diff(date1, date2, unit) → จำนวนวันระหว่างสองวัน assert_eq!(eval("date_diff(\"2023-01-01\", \"2023-01-05\", \"days\")"), Value::Number(4.0)); // year / month / day → ดึงส่วนจากวันที่ assert_eq!(eval("year(\"2023-05-15\")"), Value::Number(2023.0)); assert_eq!(eval("month(\"2023-05-15\")"), Value::Number(5.0)); assert_eq!(eval("day(\"2023-05-15\")"), Value::Number(15.0)); // now() → timestamp ปัจจุบัน (ผลลัพธ์เปลี่ยนตามเวลา) let now_result = eval("now()"); if let Value::String(s) = now_result { assert!(s.contains('T')); // ISO 8601 format } // ใช้ร่วมกับ if เพื่อตรวจสอบปี let result = eval("if(year(\"2024-01-01\") == 2024, \"ปีถูกต้อง\", \"ผิดปี\")"); assert_eq!(result, Value::String("ปีถูกต้อง".to_string())); ``` -------------------------------- ### Pull Request Template Source: https://github.com/bl1nk-bot/poe-sdk-rs/blob/main/CONTRIBUTING.md A markdown template for creating pull requests. It includes sections for description, type of change, testing, and a checklist for contributors. ```markdown ## Description Brief description of changes ## Type of Change - [ ] Bug fix - [ ] New feature - [ ] Breaking change - [ ] Documentation update ## Testing - [ ] All existing tests pass - [ ] New tests added - [ ] Manual testing performed ## Checklist - [ ] Code compiles without warnings - [ ] Tests pass - [ ] Documentation updated - [ ] Commit messages follow conventions ``` -------------------------------- ### Collection Functions: `sum`, `avg`, `min`, `max`, `count`, `join` Source: https://context7.com/bl1nk-bot/poe-sdk-rs/llms.txt These functions operate on arrays. `sum`, `avg`, `min`, `max` require number arrays, `join` requires string arrays and a separator, and `count` works on any array type. `avg` will error on an empty array. ```rust use formula_engine::{tokenize, parse, evaluate, Context, FunctionRegistry, Value}; use formula_engine::builtins; let mut reg = FunctionRegistry::new(); builtins::register_all(&mut reg); let ctx = Context::new(); let eval = |f: &str| { evaluate(&parse(&tokenize(f).unwrap()).unwrap(), &ctx, ®).unwrap() }; // sum: ผลรวมตัวเลขใน array assert_eq!(eval("sum([1, 2, 3, 4, 5])"), Value::Number(15.0)); assert_eq!(eval("sum([])"), Value::Number(0.0)); // array ว่าง = 0 assert_eq!(eval("sum([-1, -2, 3])"), Value::Number(0.0)); // avg: ค่าเฉลี่ย (error ถ้า array ว่าง) assert_eq!(eval("avg([10, 20, 30])"), Value::Number(20.0)); assert_eq!(eval("avg([7])"), Value::Number(7.0)); // min / max assert_eq!(eval("min([5, 2, 8, 1])"), Value::Number(1.0)); assert_eq!(eval("max([5, 2, 8, 1])"), Value::Number(8.0)); assert_eq!(eval("min([-1, -5, -3])"), Value::Number(-5.0)); // count: นับสมาชิก (รองรับทุกชนิด) assert_eq!(eval("count([1, \"a\", true, null])"), Value::Number(4.0)); assert_eq!(eval("count([])"), Value::Number(0.0)); // join: ต่อข้อความ assert_eq!(eval("join([\"Rust\", \"is\", \"fast\"], \" \")"), Value::String("Rust is fast".to_string())); assert_eq!(eval("join([\"a\", \"b\", \"c\"], \"\")"), Value::String("abc".to_string())); // error: avg กับ array ว่าง → E011 let t = tokenize("avg([])").unwrap(); let err = evaluate(&parse(&t).unwrap(), &ctx, ®).unwrap_err(); assert_eq!(err.code, "E011"); ``` -------------------------------- ### Handle Lexical Errors (`LexError`) Source: https://context7.com/bl1nk-bot/poe-sdk-rs/llms.txt Demonstrates how to catch a `LexError` (E001) which occurs when an unrecognized character is encountered during tokenization. Asserts the error kind and checks for the presence of span information. ```rust use formula_engine::{tokenize, parse, evaluate, Context, FunctionRegistry}; use formula_engine::error::{ErrorKind, FormulaError}; use formula_engine::builtins; let mut reg = FunctionRegistry::new(); builtins::register_all(&mut reg); let ctx = Context::new(); // E001 - LexError: อักขระไม่รู้จัก let err = tokenize("a @ b").unwrap_err(); assert_eq!(err.kind, ErrorKind::LexError); assert_eq!(err.code, "E001"); assert!(err.span.is_some()); // มีตำแหน่งบรรทัด/คอลัมน์ ``` -------------------------------- ### Handle Division by Zero Errors (`EvalError` E010) Source: https://context7.com/bl1nk-bot/poe-sdk-rs/llms.txt Demonstrates catching an `EvalError` (E010) that occurs during evaluation, specifically when attempting to divide by zero. This snippet attempts to evaluate `5 / 0`. ```rust use formula_engine::{tokenize, parse, evaluate, Context, FunctionRegistry}; use formula_engine::error::{ErrorKind, FormulaError}; use formula_engine::builtins; let mut reg = FunctionRegistry::new(); builtins::register_all(&mut reg); let ctx = Context::new(); // E010 - EvalError: หารด้วยศูนย์ let tokens = tokenize("5 / 0").unwrap(); let ast = parse(&tokens).unwrap(); let err = evaluate(&ast, &ctx, ®).unwrap_err(); assert_eq!(err.code, "E010"); ``` -------------------------------- ### Conventional Commit Message Format Source: https://github.com/bl1nk-bot/poe-sdk-rs/blob/main/CONTRIBUTING.md Follows the conventional commit format for consistent and understandable commit messages. Includes types like 'feat', 'fix', 'docs', etc. ```text type(scope): description [optional body] [optional footer] ``` ```text feat(parser): add support for array literals fix(eval): correct division by zero handling docs(api): update function documentation ``` -------------------------------- ### Poe SDK Formula Engine Project Structure Source: https://github.com/bl1nk-bot/poe-sdk-rs/blob/main/README.md Directory layout for the formula engine component of the Poe SDK, detailing the purpose of each module. ```text formula_engine/ ├── src/ │ ├── lib.rs # จุดเข้าใช้งานหลักและ re-export │ ├── lexer.rs # Lexer: แปลง string → tokens │ ├── parser.rs # Parser: แปลง tokens → AST │ ├── ast.rs # นิยามโครงสร้าง AST │ ├── eval.rs # Evaluator: ประเมินค่า AST │ ├── value.rs # นิยามชนิดข้อมูล Value │ ├── context.rs # Context: จัดการตัวแปร │ ├── functions.rs # Function Registry │ ├── error.rs # นิยามข้อผิดพลาด │ ├── span.rs # ข้อมูลตำแหน่ง (บรรทัด/คอลัมน์) │ ├── diagnostics.rs # ระบบวินิจฉัยข้อผิดพลาด │ └── builtins/ # ฟังก์ชันพื้นฐาน │ ├── mod.rs │ ├── string.rs # ฟังก์ชันข้อความ │ ├── math.rs # ฟังก์ชันคณิตศาสตร์ │ ├── logic.rs # ฟังก์ชันตรรกะ │ ├── date.rs # ฟังก์ชันวันที่ │ └── collection.rs # ฟังก์ชันคอลเลกชัน ├── docs/ # เอกสารประกอบ ├── Cargo.toml ├── LICENSE ├── README.md ├── SPEC.md # ข้อมูลจำเพาะทางเทคนิค └── PLAN.md # แผนงานการพัฒนา ``` -------------------------------- ### Parse Tokens into AST Source: https://context7.com/bl1nk-bot/poe-sdk-rs/llms.txt Converts a sequence of tokens into an Abstract Syntax Tree (AST), correctly handling operator precedence and associativity. Supports parsing mathematical formulas, function calls, array literals, and map literals. Reports parsing errors, such as mismatched parentheses. ```rust use formula_engine::{tokenize, parse}; use formula_engine::ast::Expr; // parse สูตรคณิตศาสตร์ - ได้ AST แทน (1 + (2 * 3)) let tokens = tokenize("1 + 2 * 3").unwrap(); let ast = parse(&tokens).unwrap(); // ast.expr จะเป็น BinaryExpr { op: Add, left: 1, right: BinaryExpr { op: Mul, ... } } // parse function call let tokens = tokenize("len(\"hello\")").unwrap(); let ast = parse(&tokens).unwrap(); match ast.expr { Expr::FunctionCall { name, args } => { assert_eq!(name, "len"); assert_eq!(args.len(), 1); } _ => panic!("expected function call"), } // parse array literal let tokens = tokenize("[1 + 2, 3 * 4]").unwrap(); let ast = parse(&tokens).unwrap(); match ast.expr { Expr::ArrayLiteral(elems) => assert_eq!(elems.len(), 2), _ => panic!("expected array"), } // parse map literal let tokens = tokenize("{name: \"Alice\", score: 95}").unwrap(); let ast = parse(&tokens).unwrap(); match ast.expr { Expr::MapLiteral(pairs) => { assert_eq!(pairs.len(), 2); assert_eq!(pairs[0].0, "name"); assert_eq!(pairs[1].0, "score"); } _ => panic!("expected map"), } // กรณี error: วงเล็บไม่ปิด let tokens = tokenize("1 + (2 * 3").unwrap(); let result = parse(&tokens); assert!(result.is_err()); assert_eq!(result.unwrap_err().code, "E002"); // ParseError ``` -------------------------------- ### parse(tokens: &[Token]) -> Result Source: https://context7.com/bl1nk-bot/poe-sdk-rs/llms.txt Converts a sequence of tokens into an Abstract Syntax Tree (AST), correctly handling operator precedence and associativity. It uses a recursive descent parser. ```APIDOC ## parse(tokens: &[Token]) -> Result ### Description Converts a sequence of tokens into an Abstract Syntax Tree (AST), correctly handling operator precedence and associativity. It uses a recursive descent parser with the following precedence order: parentheses > unary > `* /` > `+ -` > comparison > equality > `&&` > `||`. ### Method Rust Function ### Parameters - **tokens** (`&[Token]`) - A slice of tokens generated by the `tokenize` function. ### Response - **Ok(SpannedExpr)**: The Abstract Syntax Tree representation of the formula if parsing is successful. - **Err(FormulaError)**: An error if parsing fails, including details about the error code and position. ### Request Example ```rust use formula_engine::{tokenize, parse}; use formula_engine::ast::Expr; // parse a mathematical formula - results in AST for (1 + (2 * 3)) let tokens = tokenize("1 + 2 * 3").unwrap(); let ast = parse(&tokens).unwrap(); // ast.expr will be BinaryExpr { op: Add, left: 1, right: BinaryExpr { op: Mul, ... } } // parse a function call let tokens = tokenize("len(\"hello\")").unwrap(); let ast = parse(&tokens).unwrap(); match ast.expr { Expr::FunctionCall { name, args } => { assert_eq!(name, "len"); assert_eq!(args.len(), 1); } _ => panic!("expected function call"), } // parse an array literal let tokens = tokenize("[1 + 2, 3 * 4]").unwrap(); let ast = parse(&tokens).unwrap(); match ast.expr { Expr::ArrayLiteral(elems) => assert_eq!(elems.len(), 2), _ => panic!("expected array"), } // parse a map literal let tokens = tokenize("{name: \"Alice\", score: 95}").unwrap(); let ast = parse(&tokens).unwrap(); match ast.expr { Expr::MapLiteral(pairs) => { assert_eq!(pairs.len(), 2); assert_eq!(pairs[0].0, "name"); assert_eq!(pairs[1].0, "score"); } _ => panic!("expected map"), } // Error case: unclosed parenthesis let tokens = tokenize("1 + (2 * 3").unwrap(); let result = parse(&tokens); assert!(result.is_err()); assert_eq!(result.unwrap_err().code, "E002"); // ParseError ``` ``` -------------------------------- ### Formula Engine Architecture Diagram Source: https://github.com/bl1nk-bot/poe-sdk-rs/blob/main/README.md Visual representation of the formula engine's layered architecture, showing the flow from input to result. ```text ┌─────────────────┐ │ Input Layer │ ← สูตร: "1 + 2 * if(x > 0, 3, 4)" └────────┬────────┘ │ ▼ ┌─────────────────┐ │ Lexer │ → Token Stream พร้อม Span └────────┬────────┘ │ ▼ ┌─────────────────┐ │ Parser │ → AST (Abstract Syntax Tree) └────────┬────────┘ │ ▼ ┌─────────────────┐ │ Evaluator │ → Value (Number/String/Bool/Null) └────────┬────────┘ │ ▼ ┌─────────────────┐ │ Result │ └─────────────────┘ ``` -------------------------------- ### tokenize(source: &str) -> Result, FormulaError> Source: https://context7.com/bl1nk-bot/poe-sdk-rs/llms.txt Converts a formula string into a sequence of tokens with position information for accurate error reporting. This is the initial step in formula processing and supports various data types and operators. ```APIDOC ## tokenize(source: &str) -> Result, FormulaError> ### Description Converts a formula string into a sequence of tokens with position information for accurate error reporting. This is the initial step in formula processing and supports numbers, strings, booleans, null, operators, and various bracket types. ### Method Rust Function ### Parameters - **source** (`&str`) - The input formula string. ### Response - **Ok(Vec)**: A vector of tokens if tokenization is successful. - **Err(FormulaError)**: An error if tokenization fails, including details about the error code and position. ### Request Example ```rust use formula_engine::tokenize; use formula_engine::lexer::TokenKind; // tokenize a mathematical formula let tokens = tokenize("1 + 2 * 3").unwrap(); // resulting tokens: Number(1), Plus, Number(2), Star, Number(3), Eof assert_eq!(tokens.len(), 6); // tokenize an array function let tokens = tokenize("[1, 2, 3]").unwrap(); let kinds: Vec = tokens.iter().map(|t| t.kind.clone()).collect(); assert_eq!(kinds[0], TokenKind::LBracket); assert_eq!(kinds[4], TokenKind::RBracket); // tokenize a map literal let tokens = tokenize("{key: \"value\"}").unwrap(); // resulting tokens: LBrace, Identifier("key"), Colon, String("value"), RBrace, Eof // Error case: unknown character let result = tokenize("a @ b"); assert!(result.is_err()); let err = result.unwrap_err(); assert_eq!(err.code, "E001"); // LexError // Error case: unterminated string let result = tokenize("\"hello"); assert!(result.is_err()); // E001 - Missing closing quote for string ``` ``` -------------------------------- ### Handle Type Errors (`TypeError`) Source: https://context7.com/bl1nk-bot/poe-sdk-rs/llms.txt Illustrates catching a `TypeError` (E006) that occurs when an operation is attempted with incompatible data types, such as subtracting a number from a string. ```rust use formula_engine::{tokenize, parse, evaluate, Context, FunctionRegistry}; use formula_engine::error::{ErrorKind, FormulaError}; use formula_engine::builtins; let mut reg = FunctionRegistry::new(); builtins::register_all(&mut reg); let ctx = Context::new(); // E006 - TypeError: ชนิดข้อมูลไม่ตรง let tokens = tokenize(""text" - 5").unwrap(); let ast = parse(&tokens).unwrap(); let err = evaluate(&ast, &ctx, ®).unwrap_err(); assert_eq!(err.kind, ErrorKind::TypeError); assert_eq!(err.code, "E006"); ``` -------------------------------- ### Tokenize Formula String Source: https://context7.com/bl1nk-bot/poe-sdk-rs/llms.txt Converts a formula string into a sequence of tokens with accurate position information for error reporting. Handles numbers, strings, booleans, null, operators, and various bracket types. Errors are reported for unknown characters or unterminated strings. ```rust use formula_engine::tokenize; use formula_engine::lexer::TokenKind; // tokenize สูตรทางคณิตศาสตร์ let tokens = tokenize("1 + 2 * 3").unwrap(); // ได้ tokens: Number(1), Plus, Number(2), Star, Number(3), Eof assert_eq!(tokens.len(), 6); // tokenize ฟังก์ชัน array let tokens = tokenize("[1, 2, 3]").unwrap(); let kinds: Vec = tokens.iter().map(|t| t.kind.clone()).collect(); assert_eq!(kinds[0], TokenKind::LBracket); assert_eq!(kinds[4], TokenKind::RBracket); // tokenize map literal let tokens = tokenize("{key: \"value\"}").unwrap(); // ได้ tokens: LBrace, Identifier("key"), Colon, String("value"), RBrace, Eof // กรณี error: อักขระที่ไม่รู้จัก let result = tokenize("a @ b"); assert!(result.is_err()); let err = result.unwrap_err(); assert_eq!(err.code, "E001"); // LexError // กรณี error: string ไม่มีเครื่องหมายปิด let result = tokenize("\"hello"); assert!(result.is_err()); // E001 - ไม่พบเครื่องหมายปิดข้อความ ``` -------------------------------- ### Format Formula Errors with Source Snippet Source: https://context7.com/bl1nk-bot/poe-sdk-rs/llms.txt Use `format_error` to display human-readable error messages with source code snippets and caret pointers. This is useful for CLIs or editors. ```rust use formula_engine::{tokenize, parse, evaluate, Context, FunctionRegistry}; use formula_engine::diagnostics::format_error; use formula_engine::builtins; let mut reg = FunctionRegistry::new(); builtins::register_all(&mut reg); let ctx = Context::new(); let source = "1 + @ 2"; let err = tokenize(source).unwrap_err(); let msg = format_error(source, &err); println!("{}", msg); // ผลลัพธ์: // [E001] อักขระไม่รู้จัก '@' // 1 | 1 + @ 2 // ^ // ใช้ในกระบวนการ evaluate สูตรแบบ full pipeline let source2 = "score + unknown_var"; let tokens = tokenize(source2).unwrap(); let ast = parse(&tokens).unwrap(); let mut ctx2 = Context::new(); ctx2.set("score", formula_engine::Value::Number(10.0)); match evaluate(&ast, &ctx2, ®) { Ok(val) => println!("ผลลัพธ์: {:?}", val), Err(err) => { let msg = format_error(source2, &err); println!("{}", msg); // [E005] ไม่พบตัวแปร 'unknown_var' // 1 | score + unknown_var // ^ } } ``` -------------------------------- ### Handle Function Not Found Errors (`FunctionError` E007) Source: https://context7.com/bl1nk-bot/poe-sdk-rs/llms.txt Demonstrates catching a `FunctionError` (E007) when a non-existent function is called in an expression. This snippet attempts to call a function named `noFn`. ```rust use formula_engine::{tokenize, parse, evaluate, Context, FunctionRegistry}; use formula_engine::error::{ErrorKind, FormulaError}; use formula_engine::builtins; let mut reg = FunctionRegistry::new(); builtins::register_all(&mut reg); let ctx = Context::new(); // E007 - FunctionError: ฟังก์ชันไม่พบ let tokens = tokenize("noFn(1)").unwrap(); let ast = parse(&tokens).unwrap(); let err = evaluate(&ast, &ctx, ®).unwrap_err(); assert_eq!(err.code, "E007"); ``` -------------------------------- ### Logic Function in Formula Engine Source: https://github.com/bl1nk-bot/poe-sdk-rs/blob/main/README.md Shows the conditional logic function `if` which returns one of two values based on a condition. ```plaintext if(true, 1, 0) → `1` ``` -------------------------------- ### Conditional Logic with `if` Function Source: https://context7.com/bl1nk-bot/poe-sdk-rs/llms.txt The `if` function evaluates a boolean condition and returns one of two values. It always accepts three arguments: condition, value if true, and value if false. The condition must be a boolean. ```rust use formula_engine::{tokenize, parse, evaluate, Context, FunctionRegistry, Value}; use formula_engine::builtins; let mut reg = FunctionRegistry::new(); builtins::register_all(&mut reg); let mut ctx = Context::new(); ctx.set("score", Value::Number(75.0)); ctx.set("threshold", Value::Number(60.0)); let eval = |f: &str| { evaluate(&parse(&tokenize(f).unwrap()).unwrap(), &ctx, ®).unwrap() }; // เงื่อนไขพื้นฐาน assert_eq!(eval("if(true, 100, 200)"), Value::Number(100.0)); assert_eq!(eval("if(false, 100, 200)"), Value::Number(200.0)); // ใช้กับตัวแปรจาก context assert_eq!( eval("if(score >= threshold, \"ผ่าน\", \"ไม่ผ่าน\")"), Value::String("ผ่าน".to_string()) ); // if ซ้อนกัน assert_eq!( eval("if(score >= 90, \"A\", if(score >= 75, \"B\", \"C\"))"), Value::String("B".to_string()) ); // if ร่วมกับฟังก์ชันอื่น assert_eq!( eval("if(len(\"hello\") > 3 && 5 >= 5, upper(\"test\"), \"fail\")"), Value::String("TEST".to_string()) ); ``` -------------------------------- ### diagnostics::format_error Source: https://context7.com/bl1nk-bot/poe-sdk-rs/llms.txt Formats a FormulaError into a human-readable string, including a source snippet with a caret pointing to the error location. This is useful for display in editors or CLIs. ```APIDOC ## `diagnostics::format_error(source: &str, error: &FormulaError) -> String` ### Description Formats a `FormulaError` into a human-readable string, including a source snippet with a caret (`^`) pointing to the error location. This is ideal for display in editors or CLIs. ### Parameters - **source** (`&str`) - The source code string of the formula. - **error** (`&FormulaError`) - The error object to format. ### Returns - `String` - A formatted error message. ### Example ```rust use formula_engine::diagnostics::format_error; use formula_engine::FormulaError; let source = "1 + @ 2"; // Assume 'err' is a FormulaError obtained from tokenizing or parsing let err: FormulaError = /* ... */; let msg = format_error(source, &err); println!("{}", msg); // Example Output: // [E001] Unknown character '@' // 1 | 1 + @ 2 // ^ ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.