RumiCar シミュレータ v10.3.0 を公開しました。リリースノートは GitHub でも読めます。
v10.3.0
学習プログラムの処理系で、エラーが出ないまま Python や C (gcc) と違う値になる箇所・書けなかった Python と Arduino C の定石・英語モードでも日本語で出ていたエラーを直しました (Stage BK・走行物理は無改変です — 出荷コースの走行と、出荷の公式サンプル大会の結果は変わりません。公式サンプル大会の verifyHash e9f1da0b と凍結ハッシュ f0〜f3 は改修前と同じで、出荷の見本プログラムの出力と読み取り結果 (構文木) も改修前と同じです)。あなたのプログラムの動きが変わることがあります — 下の「v10.2.0 でエラー無しで走っていたが v10.3.0 でエラーになる書き方」と「エラー無しで値が変わる書き方」を確かめてください。今回は C も変わります (⑤ と、C の関数形式の int(c) の値)。① エラーの文言と深い再帰 (py・C) — 字句エラー・構文エラーも表示言語で出します (英語モードでは Lexical error: …・Syntax error (Py/C): …。v10.2.0 は英語モードでも日本語。日本語の文言と行は v10.2.0 と同じ)。ユーザー関数の呼び出しの入れ子 (loop()/setup() も 1 段) が 200 段に達したら、行番号付きの実行時エラー「関数の呼び出しが深すぎます」にしました (v10.2.0 は JS の「Maximum call stack size exceeded」が行番号なしで出ました)。字下げの深い本体では 200 段より手前でこのエラーになることがあります (何段で JS のスタックが尽きるかは本体の書き方と実行環境で変わります)。ループの外の break/continue のエラーは、loop() を持つプログラムの関数の直下でだけ loop() 向けの案内を出します (1 回だけ走るプログラムやトップレベルでは出しません)。評価ステップ上限 (無限ループ) のエラーは、その回の loop() の中で millis()/micros() を呼んでいたときだけ「millis() と micros() は loop() 1 回の中では進みません。delay() か次の loop() で待ってください」を添えます (時刻の進み方は変えていません)。② Python の構文 — ; で区切った複数の文を受け付けます (a = 1; b = 2・if x: a = 1; b = 2 は 2 つとも if の本体・global x; x = 1 と import math; x = 1 の ; の後ろも実行。v10.2.0 は構文エラーか、; の後ろを黙って捨てました)。括弧 ( [ { の中の改行は文の続きです (複数行のリスト・辞書・関数の引数)。閉じていない括弧は構文エラー「'(‘ が閉じられていません」(行=その括弧の行) です。隣り合う文字列リテラルは 1 つの文字列です (s = "a" "b" は “ab”・"y" f"{x}" も連結。v10.2.0 は 2 つ目を黙って捨てるか、呼び出しのエラーでした)。文字列の接頭辞 r/R (raw)・u/U・fr/rf を使えます (b"…" は未対応の構文エラー)。in/not in を使えます (list/tuple は要素・str は部分文字列・dict はキー)。リストの左辺 [a, b] = 1, 2 を代入します。--1・++x は単項の重ねです (--1 は 1)。左辺が 2 つ以上・右辺が 1 つの代入は右辺を分けます (a, b = "xy" は x と y)。文の後ろの同じ行の続き (x = 1 2・print "x"・ループの中の break 5) はどこでも構文エラーです。③ 書式指定 (py) — f-string と str.format の書式指定を python3 と同じ文字列にしました (x = 3.14159 の f"{x:.2f}"・"{:.2f}".format(x) が “3.14159” → “3.14”・幅・揃え・符号・,・0 埋め・e/g/%/x/b など。丸めは python3 と同じ偶数丸め)。v10.2.0 は書式指定を黙って落としていました。f"{x=}" (自己記述)・変換 !r/!s/!a・入れ子の f"{x:{w}}"、str.format の番号 {0}・名前 {a} (.format(a=1))・添字 {0[1]}・{{ }} も使えます。f-string の単独の } は構文エラーです。④ 値の意味論 (py) — and/or は被演算子の値を返します (0 and 1 は 0・[] or 0 は 0)。py の真偽は python3 と同じで、空の list・tuple・dict は偽です (if・elif・while・not・三項・and/or・bool() のどれでも。if lst: は空のとき本体を飛ばし、while q: は q が空になれば止まります。v10.2.0 は空でも真で、while q: は評価ステップ上限のエラーでした)。print・str・f-string・str.format・%s・Serial.print の bool は True/False、None は None です (v10.2.0 は true/false と 0)。None は 0 と別の値で (None == 0 は偽)、return に届かずに終わる関数の値は None です。None を算術・大小比較・添字に使うとエラーです。list/tuple の ==/!= は要素ごとに比べます ([1] == [1] は True・入れ子も同じ。in・count・index・remove も同じ規則)。0 ** -1・1 / False・1 // False・7 % False はゼロ除算のエラーです。// は python3 と同じ床除算です (1 // 0.1 は 9)。bool は count・index・remove・dict のキー・添字でも数です。list.index・list.remove の見つからない値はエラーです。range() の引数は整数だけです。⑤ C の定石 — 関数の中の static int n = 0; は最初の 1 回だけ初期化して値を保ちます (loop() の回をまたいでも保ちます。v10.2.0 は毎回初期化で f(); f(); f() が 1)。キャスト (int)x・(long)・(unsigned long)・(char)・(float)・(double)・(bool)・(void)x ((int)3.7 は 3・(float)7/2 は 3.5・#define T int の (T)x も)、数値接尾辞 1.0f・10L・10UL・10u・0x1Fu、カンマ演算子 (for (int i = 0, j = 0; i < 3; i++, j += 2)・a = 1, b = 2;・x = (a, b);・1 ? 2, 3 : 4)、%= (-7 %= 2 は -1)、sizeof(int(x)) を使えます (v10.2.0 は構文エラー)。char (この処理系では 1 文字の文字列) のキャストは文字コードです ((int)'A' は 65・(char)'A' は文字のまま)。ファイルの終わりまで閉じていない /* は字句エラー「閉じていないブロックコメント」です (v10.2.0 は後ろの setup()/loop() ごと黙って消えていました)。複合代入 (+=・%= ほか) と ++/-- は左辺の配列と添字を 1 回だけ評価します (C・py)。case 1, 2: と配列の大きさの int a[2, 3] は gcc と同じく構文エラーのままです。v10.2.0 でエラー無しで走っていたが v10.3.0 でエラーになる書き方 (多くは Python・gcc でもエラーです): (a) 200 段以上の入れ子の再帰 (def f(n): の return 1 + f(n - 1) で f(300)・C の同じ形。v10.2.0 は約 600 段まで走りました。Python の上限は 1000) (b) 文の後ろの同じ行の続き (x = 1 2・print "x"・print f"{x}"・ループの中の break 5) (c) 要素の数が合わない代入 (a, b = [1]・a, b = [1, 2, 3]) (d) f-string の単独の } (f"a}b"・f"a\}b") (e) str.format の誤り ("{}{}".format(1) は v10.2.0 で “1undefined”・"}".format() は “}”・"{0}{}".format(1, 2) は “11”・"{0!x}" はそのまま) と、型に合わない書式指定 (文字列に d・list に幅) (f) 0 ** -1・1 / False・1 // False・7 % False・0.0 ** -1.5 (v10.2.0 は Infinity・NaN) (g) None の算術・大小比較・添字・"%d" % None (v10.2.0 は 0 として計算・1 / None は 0 での除算のエラー)、list・文字列の添字の None (v10.2.0 は 0 番目)、random.choice(None) (JS のエラー文言のまま) (h) list.index・list.remove の見つからない値 (v10.2.0 は -1・何もしない) (i) range() の None・整数でない数・文字列と、式の中のステップ 0 (list(range(1, 5, None))・list(range(1, 5, 0)) は v10.2.0 で空・range(2.5) は 0,1,2) (j) C の閉じていない /* (k) C の (int);・int y = (int);。また実機 API に None を渡すと引数エラーとして扱います (RC_read(None) は -2・RC_drive(None, 100)・RC_steer(None) は 0 を返して何もしません。v10.2.0 は None を 0=LEFT/FREE と同じに扱いました)。エラーだったが v10.3.0 で動く書き方: ; で区切った文・括弧の中の改行・in/not in・接頭辞 r/u/fr・[a, b] = …・--1/++x・f"{x=}"・.format(a=1)・"y" f"{x}"・C のキャスト・数値接尾辞・カンマ演算子・%=・(void)x・sizeof(int(x))。エラー無しで値が変わる書き方 (Python・gcc と同じ値になります): py — 書式指定 (f"{x:.2f}" が “3.14159” → “3.14”)・f"{'a'!r}" (a → ‘a’)・f"a\{x}b" (a5b → a\5b)・print(True)・str(False)・"%s" % True (true → True)・print(None) (0 → None)・None == 0 (真 → 偽)・return の無い関数の値 (print で空 → None)・0 and 1 (false → 0)・[] or 0 (空の表示 → 0)・空の q の x = q or [0] (q → [0])・空の list/tuple/dict の真偽 (if lst:・not []・bool([]))・[1] == [1] (偽 → 真)・[True, 2].count(1) (0 → 1)・{1: "x"}.get(True) (見つからない → “x”)・remove(True) が最初の 1 を消す・index の start/end が効く ([1, 2, 1].index(1, 1) が 0 → 2)・range(True, 3) の値が数・1 // 0.1 (10 → 9)・"a" "b" (a → ab)・a, b = "xy" (a が “xy” → x と y)・global x; x = 1 の後ろ (0 → 1)・dict のキーの None (0 と同じキー → 別のキー)・文字列のメソッドと join の None (“0” → “None”)・複合代入の左辺の添字 (a[k()] += 1 の k() が 2 回 → 1 回)。C — 関数の中の static (f(); f(); f() が 1 → 3)・関数形式の int(c)・float(c)・bool(c) の 1 文字の値は文字コード (int('7')・float('7') が 7 → 55・int(' ') が 0 → 32・int('\t') が 0 → 9・bool('\0') が真 → 偽・c が ‘7’ の int(c) - 48 が -41 → 7・int('A') が NaN → 65。gcc/g++ と同じ)・a[i++] += 4 (v10.2.0 は i が 2 進んで隣の a[1] に書きました → i が 1 進んで a[0])。エラーの文言が変わった書き方: 閉じていない括弧 (x = (1⏎y = 2 の「’)’ を期待しましたが ‘NEWLINE’」→「'(‘ が閉じられていません」・if (1: も同じ。閉じ括弧の種類が違う x = [1, (2⏎, 3] は「'[‘ が閉じられていません」で、内側の ( を名指ししません)・.format 以外のキーワード引数 (print(x, end="") の「’)’ を期待しましたが ‘=’」→「キーワード引数 ‘end=’ は未対応です」)・len(None) (「対象は list/str/dict のみ」→「対象がありません」。日本語だけ・行番号なしのまま)・1 回だけ走るプログラムとトップレベルの continue/break (loop() 向けの案内を外しました)・C の EOF で終わる x %=・1 ,・(int) (「’;’ を期待しましたが …」→「予期しないトークン ‘EOF’」)・for (int i = 0, (→「’ID’ を期待しましたが ‘EOF’」)・sizeof(unsigned long(x)) (「’)’ を期待しましたが ‘(‘」→「… ‘long’」)。変えていないこと: global を書かずに関数の中で代入した名前は既存のグローバルを書き換えます (意図的な仕様)。C の / は真除算 ((int)7/2 は 3.5)・C の型は幅を持たない ((uint8_t)300 は 300)・C のブロック { } はスコープを作らない・C の print(true) は “true” のままです。Stage BK で直した項目と直していない Python との差は、物理モデル解説 §9 の「学習プログラムの言語意味論」に一覧しました (v10.3.0 で是正した 21 項目を「v10.3.0(Stage BK)で是正した Python との差」へ移して各項目に残る差を書き、是正していない 9 項目は v10.2.0 の番号のまま残しました)。このほか、常設の検証ゲートを 79 → 80 本にしました (wf_bk1_interp2.mjs)。
