json(vm): fix birth dispatch; unify constructor naming (Box.birth/N); JsonNode factories return JsonNodeInstance; quick: enable heavy JSON with probe; builder: NYASH_BUILDER_DEBUG_LIMIT guard; json_query_min(core) harness; docs/tasks updated
This commit is contained in:
@ -9,11 +9,62 @@ using "apps/lib/json_native/utils/escape.nyash" as EscapeUtils
|
||||
// 🌟 JSON値を表現するBox(Everything is Box原則)
|
||||
static box JsonNode {
|
||||
|
||||
// --- Internal normalization helper (dev-safe) ---
|
||||
// Convert arbitrary values (MapBox/ArrayBox/primitives) into JsonNode or null.
|
||||
// Heuristics only; keeps behavior stable without requiring the parser here.
|
||||
normalize_any_(x) {
|
||||
if x == null { return null }
|
||||
// Already a JsonNode (stringify + get_kind expected)
|
||||
if x.stringify != null and x.get_kind != null {
|
||||
return x
|
||||
}
|
||||
// MapBox → object JsonNode (key-wise wrap)
|
||||
if x.keys != null and x.get != null and x.set != null {
|
||||
local out = this.create_object()
|
||||
local ks = x.keys()
|
||||
local i = 0
|
||||
loop(i < ks.length()) {
|
||||
local k = ks.get(i)
|
||||
local v = x.get(k)
|
||||
out.object_set(k, this.normalize_any_(v))
|
||||
i = i + 1
|
||||
}
|
||||
return out
|
||||
}
|
||||
// ArrayBox → array JsonNode (index-wise wrap)
|
||||
if x.length != null and x.get != null and x.push != null {
|
||||
local out = this.create_array()
|
||||
local i = 0
|
||||
local n = x.length()
|
||||
loop(i < n) {
|
||||
out.array_push(this.normalize_any_(x.get(i)))
|
||||
i = i + 1
|
||||
}
|
||||
return out
|
||||
}
|
||||
// Primitive-ish fallback: derive from textual form
|
||||
if x.toString != null {
|
||||
local s = x.toString()
|
||||
// Fast common literals
|
||||
if s == "null" { return null }
|
||||
if s == "true" { return this.create_bool(true) }
|
||||
if s == "false" { return this.create_bool(false) }
|
||||
// Integer detection
|
||||
if StringUtils.is_integer(s) {
|
||||
return this.create_int(StringUtils.parse_integer(s))
|
||||
}
|
||||
// As a last resort, wrap as string
|
||||
return this.create_string(s)
|
||||
}
|
||||
// Unknown – safest is null
|
||||
return null
|
||||
}
|
||||
|
||||
// ===== ファクトリーメソッド =====
|
||||
|
||||
// null値を作成
|
||||
create_null() {
|
||||
local node = new JsonNode()
|
||||
local node = new JsonNodeInstance()
|
||||
node.kind = "null"
|
||||
node.value = null
|
||||
return node
|
||||
@ -21,7 +72,7 @@ static box JsonNode {
|
||||
|
||||
// bool値を作成
|
||||
create_bool(b) {
|
||||
local node = new JsonNode()
|
||||
local node = new JsonNodeInstance()
|
||||
node.kind = "bool"
|
||||
node.value = b
|
||||
return node
|
||||
@ -29,7 +80,7 @@ static box JsonNode {
|
||||
|
||||
// int値を作成
|
||||
create_int(i) {
|
||||
local node = new JsonNode()
|
||||
local node = new JsonNodeInstance()
|
||||
node.kind = "int"
|
||||
node.value = i
|
||||
return node
|
||||
@ -37,7 +88,7 @@ static box JsonNode {
|
||||
|
||||
// float値を作成(値は文字列表現を保持)
|
||||
create_float(fstr) {
|
||||
local node = new JsonNode()
|
||||
local node = new JsonNodeInstance()
|
||||
node.kind = "float"
|
||||
node.value = fstr // Phase 1: 文字列として保持(演算不要、stringify重視)
|
||||
return node
|
||||
@ -45,7 +96,7 @@ static box JsonNode {
|
||||
|
||||
// string値を作成
|
||||
create_string(s) {
|
||||
local node = new JsonNode()
|
||||
local node = new JsonNodeInstance()
|
||||
node.kind = "string"
|
||||
node.value = s
|
||||
return node
|
||||
@ -53,7 +104,7 @@ static box JsonNode {
|
||||
|
||||
// array値を作成
|
||||
create_array() {
|
||||
local node = new JsonNode()
|
||||
local node = new JsonNodeInstance()
|
||||
node.kind = "array"
|
||||
node.value = new ArrayBox()
|
||||
return node
|
||||
@ -61,7 +112,7 @@ static box JsonNode {
|
||||
|
||||
// object値を作成
|
||||
create_object() {
|
||||
local node = new JsonNode()
|
||||
local node = new JsonNodeInstance()
|
||||
node.kind = "object"
|
||||
node.value = new MapBox()
|
||||
return node
|
||||
@ -73,7 +124,7 @@ static box JsonNode {
|
||||
parse(json_text) {
|
||||
// TODO: 本格的なレクサー・パーサーは後で実装
|
||||
// まずは超シンプルな実装で動作確認
|
||||
|
||||
|
||||
// 空白をトリム(美しいモジュラー設計)
|
||||
local text = StringUtils.trim(json_text)
|
||||
|
||||
@ -95,6 +146,10 @@ static box JsonNode {
|
||||
local num = StringUtils.parse_integer(text)
|
||||
return this.create_int(num)
|
||||
}
|
||||
// 浮動小数点(簡易検出: 小数点/指数記号を含む)
|
||||
if StringUtils.contains(text, ".") or StringUtils.contains(text, "e") or StringUtils.contains(text, "E") {
|
||||
return this.create_float(text)
|
||||
}
|
||||
|
||||
// 文字列(エスケープ処理対応)
|
||||
if StringUtils.starts_with(text, "\"") and StringUtils.ends_with(text, "\"") {
|
||||
@ -111,8 +166,41 @@ static box JsonNode {
|
||||
|
||||
// オブジェクト(超シンプル版)
|
||||
if StringUtils.starts_with(text, "{") and StringUtils.ends_with(text, "}") {
|
||||
// 単一キーの素朴なハンドリング: {"k":<num|string|bool|null>}
|
||||
local object_node = this.create_object()
|
||||
// TODO: キー・バリューのパース処理は後で実装
|
||||
local inner = text.substring(1, text.length() - 1)
|
||||
inner = StringUtils.trim(inner)
|
||||
if inner.length() == 0 {
|
||||
return object_node
|
||||
}
|
||||
// 最低限の分割(コロン一箇所想定): indexOf があれば活用
|
||||
local sep = -1
|
||||
if inner.indexOf != null { sep = inner.indexOf(":") }
|
||||
if sep == -1 {
|
||||
return object_node
|
||||
}
|
||||
local kraw = StringUtils.trim(inner.substring(0, sep))
|
||||
local vraw = StringUtils.trim(inner.substring(sep + 1, inner.length()))
|
||||
// キーはダブルクォート必須(簡易)
|
||||
if StringUtils.starts_with(kraw, "\"") and StringUtils.ends_with(kraw, "\"") {
|
||||
local key = EscapeUtils.unquote_string(kraw)
|
||||
// 値は既存の簡易規則に委譲
|
||||
local val
|
||||
if vraw == "null" { val = this.create_null() } else {
|
||||
if vraw == "true" { val = this.create_bool(true) } else {
|
||||
if vraw == "false" { val = this.create_bool(false) } else {
|
||||
if StringUtils.is_integer(vraw) { val = this.create_int(StringUtils.parse_integer(vraw)) } else {
|
||||
if StringUtils.contains(vraw, ".") or StringUtils.contains(vraw, "e") or StringUtils.contains(vraw, "E") { val = this.create_float(vraw) } else {
|
||||
if StringUtils.starts_with(vraw, "\"") and StringUtils.ends_with(vraw, "\"") { val = this.create_string(EscapeUtils.unquote_string(vraw)) } else {
|
||||
val = this.create_null()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
object_node.object_set(key, val)
|
||||
}
|
||||
return object_node
|
||||
}
|
||||
|
||||
@ -159,10 +247,14 @@ static box JsonNode {
|
||||
return 0
|
||||
}
|
||||
|
||||
// 配列の要素を取得
|
||||
// 配列の要素を取得(欠損時は null を返す)
|
||||
array_get(index) {
|
||||
if me.kind == "array" {
|
||||
return me.value.get(index)
|
||||
if index >= 0 and index < me.value.length() {
|
||||
return this.normalize_any_(me.value.get(index))
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
@ -174,10 +266,14 @@ static box JsonNode {
|
||||
}
|
||||
}
|
||||
|
||||
// オブジェクトのキーを取得
|
||||
// オブジェクトのキーを取得(欠損時は null を返す)
|
||||
object_get(key) {
|
||||
if me.kind == "object" {
|
||||
return me.value.get(key)
|
||||
if me.value.has(key) {
|
||||
return this.normalize_any_(me.value.get(key))
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
@ -212,7 +308,8 @@ static box JsonNode {
|
||||
}
|
||||
} else {
|
||||
if me.kind == "int" {
|
||||
return me.value.toString()
|
||||
// Avoid relying on primitive method resolution; force string via concat
|
||||
return "" + me.value
|
||||
} else {
|
||||
if me.kind == "float" {
|
||||
// 数値の文字列表現をそのまま出力(引用符なし)
|
||||
@ -221,38 +318,61 @@ static box JsonNode {
|
||||
if me.kind == "string" {
|
||||
return EscapeUtils.quote_string(me.value)
|
||||
} else {
|
||||
if me.kind == "array" {
|
||||
local parts = new ArrayBox()
|
||||
local i = 0
|
||||
loop(i < me.value.length()) {
|
||||
local elem = me.value.get(i)
|
||||
parts.push(elem.stringify())
|
||||
i = i + 1
|
||||
}
|
||||
return "[" + StringUtils.join(parts, ",") + "]"
|
||||
} else {
|
||||
if me.kind == "object" {
|
||||
local parts = new ArrayBox()
|
||||
local keys = me.value.keys()
|
||||
local i = 0
|
||||
loop(i < keys.length()) {
|
||||
local key = keys.get(i)
|
||||
local val = me.value.get(key)
|
||||
local pair = EscapeUtils.quote_string(key) + ":" + val.stringify()
|
||||
parts.push(pair)
|
||||
i = i + 1
|
||||
}
|
||||
return "{" + StringUtils.join(parts, ",") + "}"
|
||||
} else {
|
||||
return "null"
|
||||
}
|
||||
}
|
||||
if me.kind == "array" {
|
||||
local parts = new ArrayBox()
|
||||
local i = 0
|
||||
loop(i < me.value.length()) {
|
||||
local elem = me.value.get(i)
|
||||
parts.push(elem.stringify())
|
||||
i = i + 1
|
||||
}
|
||||
return "[" + StringUtils.join(parts, ",") + "]"
|
||||
} else {
|
||||
if me.kind == "object" {
|
||||
// 安定出力のためキーを辞書順で整列
|
||||
local keys = me.value.keys()
|
||||
// 簡易バブルソート(要素数が小さい前提)
|
||||
local n = keys.length()
|
||||
local i = 0
|
||||
loop(i < n) {
|
||||
local j = 0
|
||||
loop(j + 1 < n) {
|
||||
local a = keys.get(j)
|
||||
local b = keys.get(j + 1)
|
||||
if a > b {
|
||||
// swap
|
||||
keys.set(j, b)
|
||||
keys.set(j + 1, a)
|
||||
}
|
||||
j = j + 1
|
||||
}
|
||||
i = i + 1
|
||||
}
|
||||
local parts = new ArrayBox()
|
||||
local k = 0
|
||||
loop(k < keys.length()) {
|
||||
local key = keys.get(k)
|
||||
local val = me.value.get(key)
|
||||
local pair = EscapeUtils.quote_string(key) + ":" + val.stringify()
|
||||
parts.push(pair)
|
||||
k = k + 1
|
||||
}
|
||||
return "{" + StringUtils.join(parts, ",") + "}"
|
||||
} else {
|
||||
return "null"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 互換: toString は stringify と等価
|
||||
toString() {
|
||||
return me.stringify()
|
||||
}
|
||||
|
||||
// ===== ヘルパーメソッド =====
|
||||
// 美しいモジュラー設計により、重複コードを削除
|
||||
@ -304,7 +424,8 @@ box JsonNodeInstance {
|
||||
if me.value { return "true" } else { return "false" }
|
||||
}
|
||||
if me.kind == "int" {
|
||||
return me.value.toString()
|
||||
// Avoid relying on primitive method resolution; force string via concat
|
||||
return "" + me.value
|
||||
}
|
||||
if me.kind == "float" {
|
||||
return me.value
|
||||
@ -323,21 +444,42 @@ box JsonNodeInstance {
|
||||
return "[" + StringUtils.join(parts, ",") + "]"
|
||||
}
|
||||
if me.kind == "object" {
|
||||
local parts = new ArrayBox()
|
||||
// 安定出力のためキーを辞書順で整列
|
||||
local keys = me.value.keys()
|
||||
local n = keys.length()
|
||||
local i = 0
|
||||
loop(i < keys.length()) {
|
||||
local key = keys.get(i)
|
||||
loop(i < n) {
|
||||
local j = 0
|
||||
loop(j + 1 < n) {
|
||||
local a = keys.get(j)
|
||||
local b = keys.get(j + 1)
|
||||
if a > b {
|
||||
keys.set(j, b)
|
||||
keys.set(j + 1, a)
|
||||
}
|
||||
j = j + 1
|
||||
}
|
||||
i = i + 1
|
||||
}
|
||||
local parts = new ArrayBox()
|
||||
local k = 0
|
||||
loop(k < keys.length()) {
|
||||
local key = keys.get(k)
|
||||
local val = me.value.get(key)
|
||||
local pair = EscapeUtils.quote_string(key) + ":" + val.stringify()
|
||||
parts.push(pair)
|
||||
i = i + 1
|
||||
k = k + 1
|
||||
}
|
||||
return "{" + StringUtils.join(parts, ",") + "}"
|
||||
}
|
||||
return "null"
|
||||
}
|
||||
|
||||
// 互換: toString は stringify と等価
|
||||
toString() {
|
||||
return me.stringify()
|
||||
}
|
||||
|
||||
// Instance helper: push element into array value
|
||||
array_push(node) {
|
||||
if me.kind == "array" {
|
||||
@ -353,10 +495,26 @@ box JsonNodeInstance {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Instance helper: object get
|
||||
// Instance helper: array get(欠損時は null を返す)
|
||||
array_get(index) {
|
||||
if me.kind == "array" {
|
||||
if index >= 0 and index < me.value.length() {
|
||||
return JsonNode.normalize_any_(me.value.get(index))
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// Instance helper: object get(欠損時は null を返す)
|
||||
object_get(key) {
|
||||
if me.kind == "object" {
|
||||
return me.value.get(key)
|
||||
if me.value.has(key) {
|
||||
return JsonNode.normalize_any_(me.value.get(key))
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@ -24,6 +24,15 @@ box JsonScanner {
|
||||
me.line = 1
|
||||
me.column = 1
|
||||
}
|
||||
|
||||
// Runtime-safe initializer (bypass constructor arg loss on some VM paths)
|
||||
reset_text(input_text) {
|
||||
me.text = input_text
|
||||
me.position = 0
|
||||
me.length = input_text.length()
|
||||
me.line = 1
|
||||
me.column = 1
|
||||
}
|
||||
|
||||
// ===== 基本読み取りメソッド =====
|
||||
|
||||
@ -233,6 +242,10 @@ box JsonScanner {
|
||||
// 整数部分
|
||||
if me.current() == "0" {
|
||||
me.advance()
|
||||
// 先頭0の直後に数字が続くのは無効(例: 01)
|
||||
if me.is_digit_char(me.current()) {
|
||||
return null
|
||||
}
|
||||
} else {
|
||||
if me.is_digit_char(me.current()) {
|
||||
loop(not me.is_eof() and me.is_digit_char(me.current())) {
|
||||
@ -312,7 +325,10 @@ box JsonScanner {
|
||||
i = i + 1
|
||||
}
|
||||
} else {
|
||||
// 通常のエスケープ
|
||||
// 通常のエスケープ(\" \\ \/ \b \f \n \r \t のみ)
|
||||
if not (escaped == "\"" or escaped == "\\" or escaped == "/" or escaped == "b" or escaped == "f" or escaped == "n" or escaped == "r" or escaped == "t") {
|
||||
return null
|
||||
}
|
||||
me.advance()
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -15,7 +15,8 @@ box JsonTokenizer {
|
||||
birth(input_text) {
|
||||
// Avoid static module wrapper to ensure constructor args are preserved on VM path
|
||||
// (create_scanner(...) lost the argument under VM fallback in some cases)
|
||||
me.scanner = new JsonScanner(input_text)
|
||||
me.scanner = new JsonScanner("")
|
||||
me.scanner.reset_text(input_text)
|
||||
me.tokens = new ArrayBox()
|
||||
me.errors = new ArrayBox()
|
||||
}
|
||||
@ -60,6 +61,14 @@ box JsonTokenizer {
|
||||
|
||||
return me.tokens
|
||||
}
|
||||
|
||||
// Explicitly set input text (guards against constructor-arg loss)
|
||||
set_input(input_text) {
|
||||
if me.scanner == null {
|
||||
me.scanner = new JsonScanner("")
|
||||
}
|
||||
me.scanner.reset_text(input_text)
|
||||
}
|
||||
|
||||
// 次のトークンを1つ取得
|
||||
next_token() {
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
// 責務: トークン列をJsonNodeに変換、構文エラー検出、ネスト構造処理
|
||||
|
||||
using "apps/lib/json_native/lexer/tokenizer.nyash" as JsonTokenizer
|
||||
using "apps/lib/json_native/lexer/token.nyash" as JsonToken
|
||||
using "apps/lib/json_native/lexer/token.nyash" as TokenType
|
||||
using "apps/lib/json_native/core/node.nyash" as JsonNode
|
||||
using "apps/lib/json_native/utils/string.nyash" as StringUtils
|
||||
@ -35,6 +34,8 @@ box JsonParser {
|
||||
|
||||
// Step 1: 字句解析
|
||||
local tokenizer = new JsonTokenizer(json_text)
|
||||
// Guard: ensure scanner has the correct input even if constructor args are dropped
|
||||
tokenizer.set_input(json_text)
|
||||
me.tokens = tokenizer.tokenize()
|
||||
|
||||
// 字句解析エラーをチェック
|
||||
@ -76,40 +77,33 @@ box JsonParser {
|
||||
|
||||
local token_type = token.get_type()
|
||||
|
||||
// リテラル値
|
||||
// リテラル値・構造のディスパッチ(厳密一致)
|
||||
if token_type == "NULL" {
|
||||
me.advance()
|
||||
return JsonNode.create_null()
|
||||
} else {
|
||||
if token_type == "TRUE" {
|
||||
me.advance()
|
||||
return JsonNode.create_bool(true)
|
||||
} else {
|
||||
if token_type == "FALSE" {
|
||||
me.advance()
|
||||
return JsonNode.create_bool(false)
|
||||
} else {
|
||||
if token_type == "NUMBER" {
|
||||
return me.parse_number()
|
||||
} else {
|
||||
if token_type == "STRING" {
|
||||
return me.parse_string()
|
||||
} else {
|
||||
if token_type == "LBRACE" {
|
||||
return me.parse_object()
|
||||
} else {
|
||||
if token_type == "LBRACKET" {
|
||||
return me.parse_array()
|
||||
} else {
|
||||
me.add_error("Expected JSON value, got: " + token_type)
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if token_type == "TRUE" {
|
||||
me.advance()
|
||||
return JsonNode.create_bool(true)
|
||||
}
|
||||
if token_type == "FALSE" {
|
||||
me.advance()
|
||||
return JsonNode.create_bool(false)
|
||||
}
|
||||
if token_type == "NUMBER" {
|
||||
return me.parse_number()
|
||||
}
|
||||
if token_type == "STRING" {
|
||||
return me.parse_string()
|
||||
}
|
||||
if token_type == "LBRACE" {
|
||||
return me.parse_object()
|
||||
}
|
||||
if token_type == "LBRACKET" {
|
||||
return me.parse_array()
|
||||
}
|
||||
me.add_error("Expected JSON value, got: " + token_type)
|
||||
return null
|
||||
}
|
||||
|
||||
// ===== 専用パーサーメソッド =====
|
||||
@ -117,7 +111,7 @@ box JsonParser {
|
||||
// 数値解析
|
||||
parse_number() {
|
||||
local token = me.current_token()
|
||||
if token == null or token.get_type() != TokenType.NUMBER() {
|
||||
if token == null or token.get_type() != "NUMBER" {
|
||||
me.add_error("Expected number token")
|
||||
return null
|
||||
}
|
||||
@ -142,7 +136,7 @@ box JsonParser {
|
||||
// 文字列解析
|
||||
parse_string() {
|
||||
local token = me.current_token()
|
||||
if token == null or token.get_type() != TokenType.STRING() {
|
||||
if token == null or token.get_type() != "STRING" {
|
||||
me.add_error("Expected string token")
|
||||
return null
|
||||
}
|
||||
@ -156,7 +150,7 @@ box JsonParser {
|
||||
// オブジェクト解析
|
||||
parse_object() {
|
||||
local start_token = me.current_token()
|
||||
if start_token == null or start_token.get_type() != TokenType.LBRACE() {
|
||||
if start_token == null or start_token.get_type() != "LBRACE" {
|
||||
me.add_error("Expected '{' to start object")
|
||||
return null
|
||||
}
|
||||
@ -173,7 +167,7 @@ box JsonParser {
|
||||
loop(true) {
|
||||
// キー解析
|
||||
local key_token = me.current_token()
|
||||
if key_token == null or key_token.get_type() != TokenType.STRING() {
|
||||
if key_token == null or key_token.get_type() != "STRING" {
|
||||
me.add_error("Expected string key in object")
|
||||
return null
|
||||
}
|
||||
@ -181,7 +175,7 @@ box JsonParser {
|
||||
me.advance()
|
||||
|
||||
// コロン
|
||||
if not me.match_token(TokenType.COLON()) {
|
||||
if not me.match_token("COLON") {
|
||||
me.add_error("Expected ':' after object key")
|
||||
return null
|
||||
}
|
||||
@ -196,11 +190,11 @@ box JsonParser {
|
||||
object_node.object_set(key, value)
|
||||
|
||||
// 継続判定
|
||||
if me.match_token(TokenType.COMMA()) {
|
||||
if me.match_token("COMMA") {
|
||||
// 次のキー・値ペアに続く
|
||||
continue
|
||||
} else {
|
||||
if me.match_token(TokenType.RBRACE()) {
|
||||
if me.match_token("RBRACE") {
|
||||
break // オブジェクト終了
|
||||
} else {
|
||||
me.add_error("Expected ',' or '}' in object")
|
||||
@ -215,7 +209,7 @@ box JsonParser {
|
||||
// 配列解析
|
||||
parse_array() {
|
||||
local start_token = me.current_token()
|
||||
if start_token == null or start_token.get_type() != TokenType.LBRACKET() {
|
||||
if start_token == null or start_token.get_type() != "LBRACKET" {
|
||||
me.add_error("Expected '[' to start array")
|
||||
return null
|
||||
}
|
||||
@ -224,7 +218,7 @@ box JsonParser {
|
||||
local array_node = JsonNode.create_array()
|
||||
|
||||
// 空配列チェック
|
||||
if me.match_token(TokenType.RBRACKET()) {
|
||||
if me.match_token("RBRACKET") {
|
||||
return array_node
|
||||
}
|
||||
|
||||
@ -240,11 +234,11 @@ box JsonParser {
|
||||
array_node.array_push(value)
|
||||
|
||||
// 継続判定
|
||||
if me.match_token(TokenType.COMMA()) {
|
||||
if me.match_token("COMMA") {
|
||||
// 次の要素に続く
|
||||
continue
|
||||
} else {
|
||||
if me.match_token(TokenType.RBRACKET()) {
|
||||
if me.match_token("RBRACKET") {
|
||||
break // 配列終了
|
||||
} else {
|
||||
me.add_error("Expected ',' or ']' in array")
|
||||
@ -284,9 +278,8 @@ box JsonParser {
|
||||
// 指定されたトークンタイプにマッチするかチェック(マッチしたら消費)
|
||||
match_token(expected_type) {
|
||||
local token = me.current_token()
|
||||
if token != null and token.get_type() == expected_type {
|
||||
me.advance()
|
||||
return true
|
||||
if token != null {
|
||||
if token.get_type() == expected_type { me.advance() return true }
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user