hv1: early-exit at main (no plugin init); tokenizer: Stage-3 single-quote + full escapes (\/ \b \f \' \r fix); builder: route BinOp via SSOT emit_binop_to_dst; hv1 verify canary route (builder→Core); docs: phase-20.39 updates

This commit is contained in:
nyash-codex
2025-11-04 20:46:43 +09:00
parent 31ce798341
commit 44a5158a14
53 changed files with 2237 additions and 179 deletions

View File

@ -149,11 +149,12 @@ impl NyashTokenizer {
}
Some('"') => {
let string_value = self.read_string()?;
Ok(Token::new(
TokenType::STRING(string_value),
start_line,
start_column,
))
Ok(Token::new(TokenType::STRING(string_value), start_line, start_column))
}
// Stage3: シングルクォート文字列(オプトイン)
Some('\'') if crate::config::env::parser_stage3() => {
let string_value = self.read_single_quoted_string()?;
Ok(Token::new(TokenType::STRING(string_value), start_line, start_column))
}
Some(c) if c.is_ascii_digit() => {
let token_type = self.read_numeric_literal()?;

View File

@ -1,16 +1,17 @@
use super::{NyashTokenizer, TokenizeError};
impl NyashTokenizer {
/// 文字列リテラルを読み取り
pub(crate) fn read_string(&mut self) -> Result<String, TokenizeError> {
/// 文字列リテラルを読み取り(区切り文字 quote を指定可: '"' or '\''
fn read_string_with_quote(&mut self, quote: char) -> Result<String, TokenizeError> {
let start_line = self.line;
self.advance(); // 開始の '"' をスキップ
// 開始の quote をスキップ
self.advance();
let mut string_value = String::new();
while let Some(c) = self.current_char() {
if c == '"' {
self.advance(); // 終了の '"' をスキップ
if c == quote {
self.advance(); // 終了の quote をスキップ
return Ok(string_value);
}
@ -21,11 +22,17 @@ impl NyashTokenizer {
Some('n') => string_value.push('\n'),
Some('t') => string_value.push('\t'),
Some('r') => string_value.push('\r'),
Some('b') => string_value.push('\u{0008}'), // backspace
Some('f') => string_value.push('\u{000C}'), // form feed
Some('\\') => string_value.push('\\'),
Some('"') => string_value.push('"'),
Some(c) => {
Some('\'') => string_value.push('\''), // 1-quote: エスケープされたシングルクォート
Some('/') => string_value.push('/'), // \/ を許容
// TODO: 将来 `\uXXXX` デコード既定OFF
Some(c2) => {
// 未知のエスケープはそのまま残す(互換性維持)
string_value.push('\\');
string_value.push(c);
string_value.push(c2);
}
None => break,
}
@ -38,5 +45,14 @@ impl NyashTokenizer {
Err(TokenizeError::UnterminatedString { line: start_line })
}
}
/// 既存互換: ダブルクォート専用のリーダ(内部で read_string_with_quote を呼ぶ)
pub(crate) fn read_string(&mut self) -> Result<String, TokenizeError> {
self.read_string_with_quote('"')
}
/// シングルクォート文字列の読み取りStage3 の文法拡張)
pub(crate) fn read_single_quoted_string(&mut self) -> Result<String, TokenizeError> {
self.read_string_with_quote('\'')
}
}