🚀 主要機能: • Everything is Box哲学による革新的アーキテクチャ • WebAssemblyブラウザー対応プレイグラウンド • アーティスト協同制作デモ - 複数Boxインスタンス実証 • 視覚的デバッグシステム - DebugBox完全統合 • static box Mainパターン - メモリ安全設計 ⚡ 言語機能: • NOT/AND/OR/除算演算子完全実装 • ジェネリクス/テンプレートシステム • 非同期処理(nowait/await) • try/catchエラーハンドリング • Canvas統合グラフィックス 🎨 ブラウザー体験: • 9種類のインタラクティブデモ • リアルタイムコード実行 • WebCanvas/WebConsole/WebDisplay • モバイル対応完了 🤖 Built with Claude Code collaboration Ready for public release!
367 lines
9.2 KiB
Plaintext
367 lines
9.2 KiB
Plaintext
// 🧮 Nyash数式パーサー - Everything is Box哲学による実装
|
||
// 再帰下降構文解析 + デバッグ機能付き
|
||
|
||
print("🧮 === Nyash Calculator App ===")
|
||
|
||
// デバッグ機能初期化
|
||
DEBUG = new DebugBox()
|
||
DEBUG.startTracking()
|
||
|
||
// 🎯 トークンBox - すべてのトークンがBox
|
||
box Token<T> {
|
||
init { type, value, position }
|
||
|
||
Token(tokenType, tokenValue) {
|
||
me.type = tokenType
|
||
me.value = tokenValue
|
||
me.position = 0
|
||
}
|
||
|
||
toString() {
|
||
return "Token(" + me.type + ": " + me.value + ")"
|
||
}
|
||
|
||
isType(expectedType) {
|
||
return me.type == expectedType
|
||
}
|
||
}
|
||
|
||
// 🔢 数値トークン専用Box
|
||
box NumberToken from Token<IntegerBox> {
|
||
init { numValue }
|
||
|
||
NumberToken(value) {
|
||
super("NUMBER", value)
|
||
me.numValue = value
|
||
}
|
||
|
||
getValue() {
|
||
return me.numValue
|
||
}
|
||
}
|
||
|
||
// ➕ 演算子トークン専用Box
|
||
box OperatorToken from Token<StringBox> {
|
||
init { operator, precedence }
|
||
|
||
OperatorToken(op) {
|
||
super("OPERATOR", op)
|
||
me.operator = op
|
||
|
||
// 演算子優先度設定
|
||
if op == "+" || op == "-" {
|
||
me.precedence = 1
|
||
}
|
||
if op == "*" || op == "/" {
|
||
me.precedence = 2
|
||
}
|
||
}
|
||
|
||
getPrecedence() {
|
||
return me.precedence
|
||
}
|
||
}
|
||
|
||
// 📝 字句解析器Box
|
||
box Tokenizer {
|
||
init { input, position, tokens }
|
||
|
||
Tokenizer(expression) {
|
||
me.input = expression
|
||
me.position = 0
|
||
me.tokens = new ArrayBox()
|
||
}
|
||
|
||
// 次の文字を取得
|
||
peek() {
|
||
if me.position >= me.input.length() {
|
||
return ""
|
||
}
|
||
return me.input.charAt(me.position)
|
||
}
|
||
|
||
// 文字を消費して進む
|
||
advance() {
|
||
me.position = me.position + 1
|
||
}
|
||
|
||
// 空白をスキップ
|
||
skipWhitespace() {
|
||
loop(me.position < me.input.length() && me.peek() == " ") {
|
||
me.advance()
|
||
}
|
||
}
|
||
|
||
// 数値を読み取り
|
||
readNumber() {
|
||
start = me.position
|
||
|
||
loop(me.position < me.input.length()) {
|
||
char = me.peek()
|
||
if char >= "0" && char <= "9" {
|
||
me.advance()
|
||
} else {
|
||
break
|
||
}
|
||
}
|
||
|
||
numberStr = me.input.substring(start, me.position)
|
||
return new NumberToken(numberStr.toInteger())
|
||
}
|
||
|
||
// トークン化実行
|
||
tokenize() {
|
||
loop(me.position < me.input.length()) {
|
||
me.skipWhitespace()
|
||
|
||
if me.position >= me.input.length() {
|
||
break
|
||
}
|
||
|
||
char = me.peek()
|
||
|
||
// 数値の場合
|
||
if char >= "0" && char <= "9" {
|
||
token = me.readNumber()
|
||
me.tokens.push(token)
|
||
DEBUG.trackBox(token, "number_token_" + me.tokens.length())
|
||
}
|
||
// 演算子の場合
|
||
else if char == "+" || char == "-" || char == "*" || char == "/" {
|
||
token = new OperatorToken(char)
|
||
me.tokens.push(token)
|
||
me.advance()
|
||
DEBUG.trackBox(token, "operator_token_" + me.tokens.length())
|
||
}
|
||
// 括弧の場合
|
||
else if char == "(" || char == ")" {
|
||
token = new Token("PAREN", char)
|
||
me.tokens.push(token)
|
||
me.advance()
|
||
DEBUG.trackBox(token, "paren_token_" + me.tokens.length())
|
||
}
|
||
else {
|
||
print("❌ Unknown character: " + char)
|
||
me.advance()
|
||
}
|
||
}
|
||
|
||
// 終端トークン追加
|
||
eofToken = new Token("EOF", "")
|
||
me.tokens.push(eofToken)
|
||
|
||
return me.tokens
|
||
}
|
||
|
||
printTokens() {
|
||
print("🎯 Tokens:")
|
||
i = 0
|
||
loop(i < me.tokens.length()) {
|
||
token = me.tokens.get(i)
|
||
print(" " + i + ": " + token.toString())
|
||
i = i + 1
|
||
}
|
||
}
|
||
}
|
||
|
||
// 🔍 構文解析器Box - 再帰下降パーサー
|
||
box Parser {
|
||
init { tokens, position }
|
||
|
||
Parser(tokenList) {
|
||
me.tokens = tokenList
|
||
me.position = 0
|
||
}
|
||
|
||
// 現在のトークンを取得
|
||
currentToken() {
|
||
if me.position >= me.tokens.length() {
|
||
return new Token("EOF", "")
|
||
}
|
||
return me.tokens.get(me.position)
|
||
}
|
||
|
||
// トークンを消費して進む
|
||
consume() {
|
||
me.position = me.position + 1
|
||
}
|
||
|
||
// 指定したタイプのトークンを期待して消費
|
||
expect(expectedType) {
|
||
token = me.currentToken()
|
||
if token.isType(expectedType) {
|
||
me.consume()
|
||
return token
|
||
}
|
||
print("❌ Parse error: Expected " + expectedType + ", got " + token.type)
|
||
return null
|
||
}
|
||
|
||
// 式の解析 (+ と -)
|
||
parseExpression() {
|
||
DEBUG.traceCall("parseExpression", "", "")
|
||
|
||
result = me.parseTerm()
|
||
|
||
loop(true) {
|
||
token = me.currentToken()
|
||
if token.isType("OPERATOR") {
|
||
op = token.value
|
||
if op == "+" || op == "-" {
|
||
me.consume()
|
||
right = me.parseTerm()
|
||
|
||
if op == "+" {
|
||
result = result + right
|
||
} else {
|
||
result = result - right
|
||
}
|
||
|
||
print("📊 " + op + " operation: result = " + result)
|
||
} else {
|
||
break
|
||
}
|
||
} else {
|
||
break
|
||
}
|
||
}
|
||
|
||
return result
|
||
}
|
||
|
||
// 項の解析 (* と /)
|
||
parseTerm() {
|
||
DEBUG.traceCall("parseTerm", "", "")
|
||
|
||
result = me.parseFactor()
|
||
|
||
loop(true) {
|
||
token = me.currentToken()
|
||
if token.isType("OPERATOR") {
|
||
op = token.value
|
||
if op == "*" || op == "/" {
|
||
me.consume()
|
||
right = me.parseFactor()
|
||
|
||
if op == "*" {
|
||
result = result * right
|
||
} else {
|
||
if right == 0 {
|
||
print("❌ Division by zero!")
|
||
return 0
|
||
}
|
||
result = result / right
|
||
}
|
||
|
||
print("📊 " + op + " operation: result = " + result)
|
||
} else {
|
||
break
|
||
}
|
||
} else {
|
||
break
|
||
}
|
||
}
|
||
|
||
return result
|
||
}
|
||
|
||
// 因子の解析 (数値と括弧)
|
||
parseFactor() {
|
||
DEBUG.traceCall("parseFactor", "", "")
|
||
|
||
token = me.currentToken()
|
||
|
||
// 数値
|
||
if token.isType("NUMBER") {
|
||
me.consume()
|
||
value = token.value.toInteger()
|
||
print("🔢 Number: " + value)
|
||
return value
|
||
}
|
||
// 括弧
|
||
else if token.isType("PAREN") && token.value == "(" {
|
||
me.consume() // consume '('
|
||
result = me.parseExpression()
|
||
me.expect("PAREN") // expect ')'
|
||
return result
|
||
}
|
||
// エラー
|
||
else {
|
||
print("❌ Parse error: Unexpected token " + token.toString())
|
||
return 0
|
||
}
|
||
}
|
||
|
||
// 構文解析実行
|
||
parse() {
|
||
print("🚀 Starting parse...")
|
||
result = me.parseExpression()
|
||
|
||
// 最後にEOFトークンがあることを確認
|
||
if !me.currentToken().isType("EOF") {
|
||
print("⚠️ Warning: Extra tokens after expression")
|
||
}
|
||
|
||
return result
|
||
}
|
||
}
|
||
|
||
// 🧮 メイン計算機Box
|
||
box Calculator {
|
||
init { name }
|
||
|
||
Calculator() {
|
||
me.name = "Nyash Calculator"
|
||
}
|
||
|
||
// 式を評価
|
||
evaluate(expression) {
|
||
print("\n📝 Evaluating: " + expression)
|
||
|
||
// Step 1: トークン化
|
||
tokenizer = new Tokenizer(expression)
|
||
DEBUG.trackBox(tokenizer, "main_tokenizer")
|
||
|
||
tokens = tokenizer.tokenize()
|
||
tokenizer.printTokens()
|
||
|
||
// Step 2: 構文解析・評価
|
||
parser = new Parser(tokens)
|
||
DEBUG.trackBox(parser, "main_parser")
|
||
|
||
result = parser.parse()
|
||
|
||
print("✅ Result: " + result)
|
||
return result
|
||
}
|
||
}
|
||
|
||
// 🚀 アプリケーション実行
|
||
print("🎯 Testing Nyash Calculator...")
|
||
|
||
calc = new Calculator()
|
||
DEBUG.trackBox(calc, "main_calculator")
|
||
|
||
// テスト式
|
||
testExpressions = new ArrayBox()
|
||
testExpressions.push("2 + 3")
|
||
testExpressions.push("5 * 4")
|
||
testExpressions.push("10 - 6")
|
||
testExpressions.push("15 / 3")
|
||
testExpressions.push("2 + 3 * 4")
|
||
testExpressions.push("(2 + 3) * 4")
|
||
|
||
// すべてのテスト実行
|
||
i = 0
|
||
loop(i < testExpressions.length()) {
|
||
expression = testExpressions.get(i)
|
||
calc.evaluate(expression)
|
||
i = i + 1
|
||
}
|
||
|
||
// デバッグ情報表示
|
||
print("\n📊 === Debug Report ===")
|
||
print(DEBUG.memoryReport())
|
||
print(DEBUG.showCallStack())
|
||
|
||
print("\n🎉 Calculator app completed!") |