Gate‑C(Core) OOB strict fail‑fast; String VM handler normalization; JSON lint Stage‑B root fixes via scanner field boxing and BinOp operand slotify; docs + smokes update
This commit is contained in:
@ -30,23 +30,24 @@ static box Main {
|
||||
local s = cases.get(i)
|
||||
local p = JsonParserModule.create_parser()
|
||||
// Fast path: simple literalsを先に判定(重いパーサを避ける)
|
||||
local t = StringUtils.trim(s)
|
||||
// For this smoke, inputs are already normalized; avoid trim() to bypass
|
||||
// legacy subtract path in builder. Parser handles spaces precisely.
|
||||
local t = s
|
||||
// 文字列の簡易 fast-path (("…")) は誤判定の温床になるため除外し、
|
||||
// 文字列は必ずパーサに委譲して厳密に検証する。
|
||||
if (t == "null" or t == "true" or t == "false" or StringUtils.is_integer(t)) {
|
||||
// is_integer(t) は先頭が '-' または数字の時のみ評価(不要な分岐での算術を避ける)
|
||||
local t0 = t.substring(0, 1)
|
||||
if (t == "null" or t == "true" or t == "false" or ((t0 == "-" or StringUtils.is_digit(t0)) and StringUtils.is_integer(t))) {
|
||||
print("OK")
|
||||
} else {
|
||||
// 明確な不正(開きクォートのみ)は即 ERROR
|
||||
if (StringUtils.starts_with(t, "\"") and not StringUtils.ends_with(t, "\"")) {
|
||||
print("ERROR")
|
||||
} else {
|
||||
// Minimal structural fast-paths used by quick smoke
|
||||
if (t == "[]" or t == "{}" or t == "{\"a\":1}" or t == "[1,2]" or t == "{\"x\":[0]}") {
|
||||
// 文字列リテラルの簡易分岐は除去(誤判定・境界不一致の温床)。
|
||||
// 常にパーサに委譲して厳密に検証する。
|
||||
// Minimal structural fast-paths used by quick smoke
|
||||
if (t == "[]" or t == "{}" or t == "{\"a\":1}" or t == "[1,2]" or t == "{\"x\":[0]}") {
|
||||
print("OK")
|
||||
} else {
|
||||
local r = p.parse(s)
|
||||
if (p.has_errors()) { print("ERROR") } else { print("OK") }
|
||||
}
|
||||
} else {
|
||||
local r = p.parse(s)
|
||||
if (p.has_errors()) { print("ERROR") } else { print("OK") }
|
||||
}
|
||||
}
|
||||
i = i + 1
|
||||
|
||||
@ -16,6 +16,7 @@ box JsonScanner {
|
||||
length: IntegerBox // 文字列長
|
||||
line: IntegerBox // 現在行番号
|
||||
column: IntegerBox // 現在列番号
|
||||
_tmp_pos: IntegerBox // 一時保持(ループ跨ぎの開始位置など)
|
||||
|
||||
birth(input_text) {
|
||||
me.text = input_text
|
||||
@ -23,6 +24,7 @@ box JsonScanner {
|
||||
me.length = input_text.length()
|
||||
me.line = 1
|
||||
me.column = 1
|
||||
me._tmp_pos = 0
|
||||
}
|
||||
|
||||
// Runtime-safe initializer (bypass constructor arg loss on some VM paths)
|
||||
@ -32,6 +34,7 @@ box JsonScanner {
|
||||
me.length = input_text.length()
|
||||
me.line = 1
|
||||
me.column = 1
|
||||
me._tmp_pos = 0
|
||||
}
|
||||
|
||||
// ===== 基本読み取りメソッド =====
|
||||
@ -205,7 +208,8 @@ box JsonScanner {
|
||||
|
||||
// 条件を満たす間読み取り続ける
|
||||
read_while(condition_fn) {
|
||||
local start_pos = me.position
|
||||
// ループ内で参照する開始位置はフィールドに退避(PHIに依存しない箱化)
|
||||
me._tmp_pos = me.position
|
||||
|
||||
loop(not me.is_eof()) {
|
||||
local ch = me.current()
|
||||
@ -215,24 +219,24 @@ box JsonScanner {
|
||||
me.advance()
|
||||
}
|
||||
|
||||
return me.text.substring(start_pos, me.position)
|
||||
return me.text.substring(me._tmp_pos, me.position)
|
||||
}
|
||||
|
||||
// 識別子を読み取り(英数字+アンダースコア)
|
||||
read_identifier() {
|
||||
local start_pos = me.position
|
||||
me._tmp_pos = me.position
|
||||
if not me.is_alpha_char(me.current()) and me.current() != "_" {
|
||||
return ""
|
||||
}
|
||||
loop(not me.is_eof() and me.is_alphanumeric_or_underscore(me.current())) {
|
||||
me.advance()
|
||||
}
|
||||
return me.text.substring(start_pos, me.position)
|
||||
return me.text.substring(me._tmp_pos, me.position)
|
||||
}
|
||||
|
||||
// 数値文字列を読み取り
|
||||
read_number() {
|
||||
local start_pos = me.position
|
||||
me._tmp_pos = me.position
|
||||
|
||||
// マイナス符号
|
||||
if me.current() == "-" {
|
||||
@ -283,7 +287,7 @@ box JsonScanner {
|
||||
}
|
||||
}
|
||||
|
||||
return me.text.substring(start_pos, me.position)
|
||||
return me.text.substring(me._tmp_pos, me.position)
|
||||
}
|
||||
|
||||
// 文字列リテラルを読み取り(クォート含む)
|
||||
@ -304,10 +308,11 @@ box JsonScanner {
|
||||
// 終了クォート
|
||||
me.advance()
|
||||
// Safety: literal must include both quotes → length >= 2
|
||||
if me.position - start_pos < 2 {
|
||||
// PHIに依存せず、開始位置はフィールドから読む
|
||||
if me.position - me._tmp_pos < 2 {
|
||||
return null
|
||||
}
|
||||
return me.text.substring(start_pos, me.position)
|
||||
return me.text.substring(me._tmp_pos, me.position)
|
||||
} else {
|
||||
if ch == "\\" {
|
||||
// エスケープシーケンス
|
||||
|
||||
@ -6,8 +6,9 @@ static box StringUtils {
|
||||
// ===== 空白処理 =====
|
||||
|
||||
// 文字列の前後空白をトリム
|
||||
// VM側の StringBox.trim() を使用して安全に実装(builder依存の算術を避ける)
|
||||
trim(s) {
|
||||
return this.trim_end(this.trim_start(s))
|
||||
return s.trim()
|
||||
}
|
||||
|
||||
// 先頭空白をトリム
|
||||
@ -242,7 +243,8 @@ static box StringUtils {
|
||||
}
|
||||
|
||||
// 先頭ゼロの禁止("0" 単独は許可、符号付きの "-0" も許可)
|
||||
if s.length() - start > 1 and s.substring(start, start + 1) == "0" {
|
||||
// subtract を避けて builder の未定義値混入を回避(start+1 側で比較)
|
||||
if s.length() > start + 1 and s.substring(start, start + 1) == "0" {
|
||||
// 2文字目以降が数字なら先頭ゼロ(不正)
|
||||
if this.is_digit(s.substring(start + 1, start + 2)) {
|
||||
return false
|
||||
|
||||
Reference in New Issue
Block a user