カテゴリー
お知らせ

RumiCar シミュレータ v10.2.0 を公開しました

RumiCar シミュレータ v10.2.0 を公開しました。リリースノートは GitHub でも読めます。


v10.2.0

学習プログラムの Python 風の処理系で、エラーが出ないまま Python と違う動きをする箇所と、読んでも原因が分からないエラーになる箇所を直しました (Stage BJ・走行物理は無改変です — 出荷コースの走行と、出荷の公式サンプル大会の結果は変わりません。公式サンプル大会の verifyHash e9f1da0b と凍結ハッシュ f0〜f3 は改修前と同じで、出荷の見本プログラム 26 本の読み取り結果 (構文木) も改修前と同じです)。あなたのプログラムの動きが変わることがあります — 下の「v10.1.0 でエラー無しで走っていたが v10.2.0 でエラーになる書き方」と「Python と違う値だったものが Python と同じ値になる書き方」を確かめてください。C は ① のエスケープと CRLF、③ の行番号と閉じていない文字列、④ のユーザー関数を呼んだ文のエラーの行、⑤ のエラーと、未対応のままの %= のエラー文言 (下の「エラーの文言が変わった書き方」) のほかは変わりません (C の true == 1 は偽・% は切り捨て剰余のまま)。① 字句・構文 — for i in range(a, b)・range(a, b, step) が 1 回も回らなかったのを直しました (引数 1 個は従来どおり。引数 4 個の range(1,2,3,4) は構文エラー)。複合代入 %=・//=・**= を使えます (py。C の %= は未対応のまま)。タプルの左辺の複合代入 a, b += 1 は構文エラーです (Python も SyntaxError)。文字列のエスケープ \n \t \r \\ \" \' \0 を解釈します (py・C・f-string・#define。v10.1.0 は "a\tb" が “atb”)。知らないエスケープは \ を落として次の文字にします ("\q" → “q”・Python は \q の 2 文字)。8 進の \012 は NUL と “12”、\x・\u は扱いません。改行が CRLF の本文 (Windows で作ったファイル・GitHub 取込) を受け付けます (v10.1.0 は py のブロックの中の空行で「予期しないトークン ‘INDENT’」、\ の行継続で「不明な文字 ”」)。CRLF の本文の文字列の中の改行は LF 1 文字です (v10.1.0 は \r が残った)。② 演算子 (py) — % は床剰余です (-7 % 2 → 1・v10.1.0 は -1)。-x**2 は -(x**2) です (-2 ** 2 → -4・v10.1.0 は 4)。True == 1 は真です (bool と数を数として比べるのは == と != だけ)。f-string の {} の中の式を Python の意味で読みます (f"{7//2}" → “3”・v10.1.0 は // から後ろを注釈として読み “7”)。f"{'\\n'}" は \ と n の 2 文字です (v10.1.0 は “n”)。f-string の式の中で文字列リテラルの外にある \ はすべて字句エラーです (f"{d[\"k\"]}"・f'{d[\'k\']}'・f"{x\t}"・f"{x\}" など。Python も SyntaxError)。③ 三重引用符と文字列の中の改行 — """…"""・'''…''' (f/F 付きを含む) を 1 つの文字列として読みます (v10.1.0 は s = """a""" が空文字列、docstring """say "hi" """ が「未定義の変数/名前: hi」)。文字列の中の改行で行番号を進めます (後ろの文のエラーの行と実行位置の表示が実際の行になります。C も同じ)。f-string の式の中の文字列の } と : で式を切りません (f"{':'}" → “:”・f"{'''it's'''}" → “it’s”)。f-string の式の中の字句エラー・構文エラーの行は実際の行、#define の置換本体の字句エラーの行は指令の行です。ファイルの終わりまで閉じていない文字列と、閉じ } の無い f-string の置換フィールドは字句エラーです。④ for・ループ・関数 (py) — for の後でループ変数と本体で作った変数が読めます (最後の値。v10.1.0 は「未定義の変数/名前」)。トップレベルの for は同名の既存のグローバルを書き換えます (i = 100 の後の for i in range(3) で i は 2・v10.1.0 は 100)。関数の中の for のループ変数は関数ローカルです (print(f(), i) が 100 100 → 2 100)。ループの後の同名の代入も関数ローカルです (下の「変えていないこと」の例外)。仮引数と同名のループ変数はループの最後の値になります (f(9) が 9 → 2)。トップレベルのループ変数が random などの名前と同じだと、ループの後もプログラムの最後までその名前を隠します。0 回のループはループ変数を作りません。while True: 型のプログラムの本体の直下の continue はその回を終え、break はループを抜けてループの後ろの文をその回に 1 回だけ走らせ、プログラムを終えます (以降は何もしません。車は最後の指令のままなので、止めるなら後ろに停止の指令を書きます。v10.1.0 は「【実行時エラー】[object Object]」で停止)。1 行で書いた if n == 2: break・else: continue・while x: break・if x: pass・elif …: break・def f(): return 1・def setup(): pass・def f(): global x・if 1: import math が動きます (v10.1.0 は「未定義の変数/名前: break」など)。ユーザー関数を呼んだ文のエラーの行と実行位置の表示は、呼ばれた関数の最後の行でなくその文の行です (x = 10 / f()・for c in f(): など。C も同じ)。1 行で書いた文のエラーの行はその文の行です (else: z = 1 / 0 は else の行)。range(a, b, 0) と range(a, b, None) は「range() のステップ (3 番目の引数) に 0 は使えません」のエラーです。⑤ ループの外の break/continue と関数の外の return — 行番号付きの読めるエラーにしました (v10.1.0 は [object Object]: トップレベル・def loop():/def setup(): の直下・while True: の直下の return・def loop(): も while True: も無い 1 回だけ走るプログラム・C の void loop(){ break; } と switch の外の break など)。ループの中から呼んだ関数の直下の break/continue もエラーです (v10.1.0 は呼び出し側のループに黙って効いた・py・C)。関数の外の return のエラーは「ループの 1 回分を終えるなら continue、ループを抜けるなら break」と案内します (py の while True: でも C の while (1) でも同じ文言)。v10.1.0 でエラー無しで走っていたが v10.2.0 でエラーになる書き方 (どれも Python でもエラーです): (a) range(1,2,3,4) (b) a, b += 1 (c) f-string の式の中で文字列リテラルの外にある \ (f"{d[\"k\"]}"・f'{d[\'k\']}'・f"{x\}"・f"{x\:>3}") (d) ループの中から呼んだ関数の直下の break/continue (py・C) (e) range(a, b, 0)・range(a, b, False)・range(a, b, None) (f) トップレベルの for random in range(2) の後の random.random() (for math in range(2) の後の math.sqrt(4) も同じ) (g) ファイルの終わりまで閉じていない文字列 (s = "abc・s = 'abc・s = """abc・'''It's・s = """a""""・s = "abc\・s = f"{x}・f"{'abc}"・f'''{x}、C の使わない #define S "abc) (h) f-string の閉じ } の無い置換フィールド (f"{x"・f"{x:'>5"。v10.1.0 は “5”) (i) 三重引用符の f-string の式の中の構文エラー・\・閉じていない文字列・閉じ } の無い置換フィールドと、式の実行時エラー (x = 0 の後の f"""a⏎{1/x}"""。v10.1.0 は三重引用符の f-string が空文字列で式を読まなかった) (j) 1 行で書いたキーワードの文の後ろの同じ行の続き (呼ばない関数の def f(): return 1 2・def f(): pass 5・条件が偽の if x: break 5)。エラーだったが v10.2.0 で動く書き方: 1 行で書いた break/continue/pass/return/global/import・while True: の直下の continue/break・for の後のループ変数と本体の変数・%=///=/**=・CRLF の本文・三重引用符の docstring に引用符があるもの。Python と違う値だったものが Python と同じ値になる書き方 (エラー無しで値が変わります): range(a, b[, step])・エスケープ・負数の %・-x**2・True == 1・f-string の式の //・f"{'\\n'}"・f"{':'}"/f"{'a:b'}"/f"{'}'}"・CRLF の本文の文字列・三重引用符 (s = """a""")・トップレベルの for と同名のグローバル (100 → 2)・関数の中の for (print(f(), i) が 2 100)・関数の中の for x の後の x = 10 (グローバルの x が 10 → 0)・仮引数と同名のループ変数 (9 → 2)・ループ変数が隠す random・1 行で書いた return 式 (v10.1.0 は条件が偽でも式を評価した: if a: return g() は a が偽でも g() を呼び、呼ばない関数の def f(): return print("side") が side を出し、トップレベルの if 0: return g() が g() を呼んだ)。Python と同じ値だったが v10.2.0 で違う値になる書き方 (1 つ): global x を書いた関数の中で x を for のループ変数にすると、ループの後の x = 10 も関数ローカルになり、グローバルの x は変わりません (v10.1.0 と Python は 10・v10.2.0 は 0。global 文を読み飛ばしているため)。同じ理由で、関数の中で x = 5 と代入してから x をループ変数にし、ループの後で x = 10 とすると、グローバルの x は v10.1.0 で 10・v10.2.0 で 5 です (Python は 0。ループより前の x = 5 がグローバルを書き換え、ループの後の x = 10 は関数ローカル)。エラーの文言が変わった書き方: C の auto s = "abc;・char c = 'a; (構文エラー → 字句エラー「閉じていない文字列」)・f"{d["k"]}" (→「f-string の { に対応する } がありません」)・f"{x\t}" (「未定義の変数/名前: xt」→ 字句エラー)・if x: break 5 (条件が真のとき「未定義の変数/名前: break」→ 構文エラー。偽のときは v10.1.0 がエラー無しで走った=上の (j))・C の a %= 2 (「予期しないトークン ‘=’」→「’;’ を期待しましたが ‘%=’」。未対応のまま)・ループの外に 1 行で書いた break/continue/return (「未定義の変数/名前」→ ⑤ のエラー)。変えていないこと: global を書かずに関数の中で代入した名前は、既存のグローバルがあればそれを書き換えます (意図的な仕様。Python は関数ローカル)。例外は ④ のとおり、その関数の中で先に for のループ変数になった名前です。Stage BJ で直していない Python との違いは物理モデル解説 §9 の「学習プログラムの言語意味論」に一覧しました (30 項目)。このほか、常設の検証ゲートを 78 → 79 本にしました (wf_bj1_pysem.mjs)。

このサイトの仕組み (v1.4.0)

一部は GitHub で公開しています:

この仕組みを面白いと思った方へ — 本丸は、ブラウザで動く自動運転シミュレータです。
シミュレータを試す → / GitHub →