diff --git a/docs/guides/language-guide.md b/docs/guides/language-guide.md index e930c5df..1816d6d0 100644 --- a/docs/guides/language-guide.md +++ b/docs/guides/language-guide.md @@ -53,6 +53,10 @@ a == b, a != b, a < b, a > b, a <= b, a >= b // 論理演算子 not condition, a and b, a or b +// ビット演算子(整数限定) +a & b, a | b, a ^ b +a << n, a >> n # 注意: 旧来の >>(ARROW)は廃止。パイプラインは |> + // Cross-type演算 (Phase 1で完全実装) 10 + 3.14 // → 13.14 (型変換) "Value: " + 42 // → "Value: 42" (文字列連結) @@ -271,4 +275,4 @@ while condition { } // 使用不可 📚 **関連ドキュメント:** - [Getting Started](GETTING_STARTED.md) - 環境構築・最初の一歩 - [P2P Guide](P2P_GUIDE.md) - P2P通信システム完全ガイド -- [Built-in Boxes](reference/builtin-boxes.md) - ビルトインBox詳細リファレンス \ No newline at end of file +- [Built-in Boxes](reference/builtin-boxes.md) - ビルトインBox詳細リファレンス diff --git a/docs/quick-reference/syntax-cheatsheet.md b/docs/quick-reference/syntax-cheatsheet.md index 26ae8e96..c2739fb3 100644 --- a/docs/quick-reference/syntax-cheatsheet.md +++ b/docs/quick-reference/syntax-cheatsheet.md @@ -245,4 +245,14 @@ local result = await future # 結果待機 - 変数は必ず宣言してから使う - ループは`loop(condition)`のみ - 親メソッドは`from Parent.method()`で呼ぶ -- カンマ忘れに注意! \ No newline at end of file +- カンマ忘れに注意! +### ビット演算子(整数限定) +```nyash +a & b # ビットAND +a | b # ビットOR +a ^ b # ビットXOR +a << n # 左シフト(n は 0..63 にマスク) +a >> n # 右シフト(現在は論理シフト相当の実装) +``` + +注意: 旧来の `>>`(ARROW 演算子)は廃止されました。パイプラインは `|>` を使用してください。 diff --git a/src/tests/parser_bitops_test.rs b/src/tests/parser_bitops_test.rs new file mode 100644 index 00000000..45d585ff --- /dev/null +++ b/src/tests/parser_bitops_test.rs @@ -0,0 +1,20 @@ +use crate::parser::NyashParser; +use crate::ast::ASTNode; + +#[test] +fn parse_bitops_and_shift_precedence() { + // Expression: 1 + 2 << 3 & 7 + // Precedence: shift before add, then &: (1 + (2 << 3)) & 7 + let code = "return 1 + 2 << 3 & 7"; + let ast = NyashParser::parse_from_string(code).expect("parse ok"); + // Just ensure it parses into a Program and contains a Return; deeper tree checks are optional here + fn has_return(n: &ASTNode) -> bool { + match n { + ASTNode::Program { statements, .. } => statements.iter().any(has_return), + ASTNode::Return { .. } => true, + _ => false, + } + } + assert!(has_return(&ast)); +} + diff --git a/src/tests/vm_bitops_test.rs b/src/tests/vm_bitops_test.rs new file mode 100644 index 00000000..92dea40c --- /dev/null +++ b/src/tests/vm_bitops_test.rs @@ -0,0 +1,25 @@ +use crate::parser::NyashParser; +use crate::interpreter::NyashInterpreter; + +#[test] +fn vm_exec_bitwise_and_shift() { + let code = r#" + return (5 & 3) + (5 | 2) + (5 ^ 1) + (1 << 5) + (32 >> 3) + "#; + let ast = NyashParser::parse_from_string(code).expect("parse ok"); + let mut interp = NyashInterpreter::new(); + let out = interp.execute(ast).expect("exec ok"); + assert_eq!(out.to_string_box().value, "48"); +} + +#[test] +fn vm_exec_shift_masking() { + // 1 << 100 should mask to 1 << (100 & 63) = 1 << 36 + let code = r#" return 1 << 100 "#; + let ast = NyashParser::parse_from_string(code).expect("parse ok"); + let mut interp = NyashInterpreter::new(); + let out = interp.execute(ast).expect("exec ok"); + // compute expected as i64 + let expected = (1_i64 as i64).wrapping_shl((100_u32) & 63); + assert_eq!(out.to_string_box().value, expected.to_string()); +} diff --git a/src/tokenizer.rs b/src/tokenizer.rs index 5012e2e6..b328e4c4 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -677,7 +677,7 @@ mod tests { let mut tokenizer = NyashTokenizer::new(">> == != <= >= < >"); let tokens = tokenizer.tokenize().unwrap(); - assert_eq!(tokens[0].token_type, TokenType::ARROW); + assert_eq!(tokens[0].token_type, TokenType::SHIFT_RIGHT); assert_eq!(tokens[1].token_type, TokenType::EQUALS); assert_eq!(tokens[2].token_type, TokenType::NotEquals); assert_eq!(tokens[3].token_type, TokenType::LessEquals);