Generate per-file top-level Java class names instead of hardcoded Main - #25
Generate per-file top-level Java class names instead of hardcoded Main #25hiroshi-cl wants to merge 2 commits into
Conversation
Every generated .java file declared `class Main`, so compiling multiple extracted files together with `javac *.java` always failed with a duplicate-class error. The class name is now derived from the module id (the same one file_naming already computes), threaded from preamble into pp_struct via a ref, mirroring the existing fix_arities side channel. mono_filename's Java branch now derives its id from the target filename the same way Haskell already does, since previously it always forced the literal "Main" id for Java regardless of the requested filename. Updates all Java extraction test fixtures accordingly and adds a run-case.sh step that compiles a case's generated files together, which would have caught this bug. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Java's top-level class name needed the module id, but the shared pp_struct signature carried none, so it was smuggled in via a top_class_name ref written by preamble and read by pp_struct (mirroring fix_arities). Add Id.t as an explicit pp_struct argument instead: OCaml/Haskell/JSON/Scheme just ignore it, and Java derives the class name directly from it, removing the ordering dependency on preamble running first. Pure refactor: all java-extraction test fixtures still match byte for byte. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
| match lang () with | ||
| | Haskell | Java -> | ||
| (* These backends name a top-level container (module / class) | ||
| after the file, so the file name must be a valid identifier. *) | ||
| (try Id.of_string (Filename.basename f) | ||
| with UserError _ -> | ||
| user_err Pp.(str "Extraction: provided filename is not a valid identifier")) | ||
| | Ocaml | Scheme | JSON -> default_id |
There was a problem hiding this comment.
HaskellだけでなくJavaもdefault_idじゃなくてfilenameを使うようにする
| 's -> Id.t -> Pp.t option -> DirPath.Set.t -> unsafe_needs -> | ||
| Pp.t; | ||
| pp_struct : 's -> ml_structure -> Pp.t; | ||
| pp_struct : 's -> Id.t -> ml_structure -> Pp.t; |
There was a problem hiding this comment.
pp_stuctを拡張してId.tを渡すようにする
haskellではpreambleとして処理しているがjavaではpp_structで出力する
これにより他の言語への抽出コードも変更が出ている
| if not valid then | ||
| user_err Pp.(str "Extraction: " ++ Id.print id ++ |
There was a problem hiding this comment.
📝
invalid な名前の場合、名前を変えるのではなくエラーにする。
| not (String.is_empty s) | ||
| && is_java_ident_start s.[0] | ||
| && String.for_all is_java_ident_part s | ||
| && not (Id.Set.mem id keywords) |
There was a problem hiding this comment.
nits な指摘
- Rocq コード内にファイル名と同じ型が定義されていると、同じ名前のクラスが2つ出てきてコンパイルが落ちそう
true / false / nullは Java のキーワードではなくリテラルなので valid な扱いとなり、しかしclass trueは javac がエラーを出す。varなども同様
There was a problem hiding this comment.
Java keyword じゃないやつも必要に応じて keywords の中に突っ込んでるから( let とか error とか)、このへんの語も全部入れてしまっても良いかも?
There was a problem hiding this comment.
確かに JLS §3.8 で reserved 以外にもBooleanLiteral (true, false), NullLiteral (null) も識別子として使えないことになってるので入れても良さそう
一方以下5つは TypeIdentifier から除外されてるけど変数とかには使えることになってそうなのでここで除外はするけどkeywordsには入れないほうが良さそう 🤔
permits
record
sealed
var
yield
cedretaber
left a comment
There was a problem hiding this comment.
2点指摘しましたが、概ね良さそうです 🙏
( Java のキーワードとそれ以外のリテラルとか、 var みたいな後から入ったのがどういう扱いなのかとか、よく分っていないのですが……。)
extractのファイル名をhaskellと同様クラス名に反映するようにします