selfhost(pyvm): MiniVmPrints – prefer JSON route early-return (ok==1) to avoid fallback loops; keep default behavior unchanged elsewhere
This commit is contained in:
@ -176,12 +176,39 @@ impl NyashParser {
|
||||
break;
|
||||
}
|
||||
|
||||
// 🔥 static { } ブロックの処理
|
||||
// 🔥 static 初期化子の処理
|
||||
// Gate: NYASH_PARSER_STATIC_INIT_STRICT=1 のとき、
|
||||
// - 直後が '{' の場合のみ static 初期化子として扱う
|
||||
// - 直後が 'box' or 'function' の場合は、トップレベル宣言の開始とみなし、この box 本体を閉じる
|
||||
// 既定(ゲートOFF)は従来挙動(常に static { ... } を期待)
|
||||
if self.match_token(&TokenType::STATIC) {
|
||||
self.advance(); // consume 'static'
|
||||
let static_body = self.parse_block_statements()?;
|
||||
static_init = Some(static_body);
|
||||
continue;
|
||||
let strict = std::env::var("NYASH_PARSER_STATIC_INIT_STRICT").ok().as_deref() == Some("1");
|
||||
if strict {
|
||||
match self.peek_token() {
|
||||
TokenType::LBRACE => {
|
||||
self.advance(); // consume 'static'
|
||||
let static_body = self.parse_block_statements()?;
|
||||
static_init = Some(static_body);
|
||||
continue;
|
||||
}
|
||||
TokenType::BOX | TokenType::FUNCTION => {
|
||||
// トップレベルの `static box|function` が続くシーム: ここで box を閉じる
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
// 不明な形は従来通り initializer として解釈(互換重視)
|
||||
self.advance();
|
||||
let static_body = self.parse_block_statements()?;
|
||||
static_init = Some(static_body);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.advance(); // consume 'static'
|
||||
let static_body = self.parse_block_statements()?;
|
||||
static_init = Some(static_body);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// initブロックの処理
|
||||
|
||||
@ -175,7 +175,50 @@ impl NyashParser {
|
||||
input: impl Into<String>,
|
||||
fuel: Option<usize>,
|
||||
) -> Result<ASTNode, ParseError> {
|
||||
let mut tokenizer = crate::tokenizer::NyashTokenizer::new(input);
|
||||
// Normalize logical operators '||'/'&&' to 'or'/'and' before tokenization (outside strings/comments)
|
||||
fn normalize_logical_ops(src: &str) -> String {
|
||||
let mut out = String::with_capacity(src.len());
|
||||
let mut it = src.chars().peekable();
|
||||
let mut in_str = false;
|
||||
let mut in_line = false;
|
||||
let mut in_block = false;
|
||||
while let Some(c) = it.next() {
|
||||
if in_line {
|
||||
out.push(c);
|
||||
if c == '\n' { in_line = false; }
|
||||
continue;
|
||||
}
|
||||
if in_block {
|
||||
out.push(c);
|
||||
if c == '*' && matches!(it.peek(), Some('/')) { out.push('/'); it.next(); in_block = false; }
|
||||
continue;
|
||||
}
|
||||
if in_str {
|
||||
out.push(c);
|
||||
if c == '\\' { if let Some(nc) = it.next() { out.push(nc); } continue; }
|
||||
if c == '"' { in_str = false; }
|
||||
continue;
|
||||
}
|
||||
match c {
|
||||
'"' => { in_str = true; out.push(c); }
|
||||
'/' => {
|
||||
match it.peek() { Some('/') => { out.push('/'); out.push('/'); it.next(); in_line = true; }, Some('*') => { out.push('/'); out.push('*'); it.next(); in_block = true; }, _ => out.push('/') }
|
||||
}
|
||||
'#' => { in_line = true; out.push('#'); }
|
||||
'|' => {
|
||||
if matches!(it.peek(), Some('|')) { out.push_str(" or "); it.next(); } else if matches!(it.peek(), Some('>')) { out.push('|'); out.push('>'); it.next(); } else { out.push('|'); }
|
||||
}
|
||||
'&' => {
|
||||
if matches!(it.peek(), Some('&')) { out.push_str(" and "); it.next(); } else { out.push('&'); }
|
||||
}
|
||||
_ => out.push(c),
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
let input_s: String = input.into();
|
||||
let pre = normalize_logical_ops(&input_s);
|
||||
let mut tokenizer = crate::tokenizer::NyashTokenizer::new(pre);
|
||||
let tokens = tokenizer.tokenize()?;
|
||||
|
||||
let mut parser = Self::new(tokens);
|
||||
|
||||
Reference in New Issue
Block a user