55import gg .moonflower .molangcompiler .api .MolangExpression ;
66import gg .moonflower .molangcompiler .api .exception .MolangException ;
77
8+ import java .util .Locale ;
89import java .util .Map ;
910import java .util .concurrent .ConcurrentHashMap ;
11+ import java .util .regex .Matcher ;
12+ import java .util .regex .Pattern ;
1013
1114final class MolangCompilerFacade {
15+ private static final Pattern NAMESPACE_IDENTIFIER = Pattern .compile (
16+ "(?i)\\ b(v|variable|ctrl|query|q|math|ysm)\\ .([a-z_][a-z0-9_]*)" );
17+ private static final Pattern SECOND_ORDER_CALL = Pattern .compile (
18+ "(?i)\\ bysm\\ .second_order\\ (\\ s*'([^']*)'\\ s*," );
19+ private static final Pattern BONE_ROTATION_CALL = Pattern .compile (
20+ "(?i)\\ bysm\\ .bone_rot\\ (\\ s*'([^']*)'\\ s*\\ )\\ s*\\ .\\ s*([xyz])\\ b" );
21+
1222 private final MolangCompiler compiler = GlobalMolangCompiler .get ();
1323 private final Map <String , MolangExpression > cache = new ConcurrentHashMap <>();
24+ private final MolangSymbolTable symbols = new MolangSymbolTable ();
1425 private final int maxEntries ;
1526 private final RateLimitedDiagnostics diagnostics ;
1627
@@ -20,7 +31,7 @@ final class MolangCompilerFacade {
2031 }
2132
2233 MolangExpression compile (String source ) {
23- String normalized = normalize (source );
34+ String normalized = rewriteDynamicFunctionArguments ( normalize (source ) );
2435 if (normalized .isBlank ()) {
2536 throw new IllegalArgumentException ("Molang expression cannot be blank" );
2637 }
@@ -40,6 +51,11 @@ MolangExpression compile(String source) {
4051
4152 void clear () {
4253 cache .clear ();
54+ symbols .clear ();
55+ }
56+
57+ MolangSymbolTable symbols () {
58+ return symbols ;
4359 }
4460
4561 int size () {
@@ -59,12 +75,48 @@ private MolangExpression compileUncached(String source) {
5975 static String normalize (String source ) {
6076 if (source == null ) return "" ;
6177 String normalized = source .trim ();
62- if (normalized .startsWith ("molang:" )) normalized = normalized .substring ("molang:" .length ()).trim ();
63- normalized = normalized .replace ("ysm.head_yaw" , "query.head_y_rotation" );
64- normalized = normalized .replace ("ysm.head_pitch" , "query.head_x_rotation" );
65- normalized = normalized .replace ("ysm.body_yaw" , "query.body_y_rotation" );
66- normalized = normalized .replace ("variable." , "v." );
67- normalized = normalized .replace ("ctrl." , "v.ctrl_" );
68- return normalized ;
78+ if (normalized .regionMatches (true , 0 , "molang:" , 0 , "molang:" .length ())) {
79+ normalized = normalized .substring ("molang:" .length ()).trim ();
80+ }
81+ normalized = normalized .replaceAll ("(?i)\\ bysm\\ .head_yaw\\ b" , "query.head_y_rotation" );
82+ normalized = normalized .replaceAll ("(?i)\\ bysm\\ .head_pitch\\ b" , "query.head_x_rotation" );
83+ normalized = normalized .replaceAll ("(?i)\\ bysm\\ .body_yaw\\ b" , "query.body_y_rotation" );
84+
85+ Matcher matcher = NAMESPACE_IDENTIFIER .matcher (normalized );
86+ StringBuffer output = new StringBuffer ();
87+ while (matcher .find ()) {
88+ String namespace = matcher .group (1 ).toLowerCase (Locale .ROOT );
89+ String member = matcher .group (2 ).toLowerCase (Locale .ROOT );
90+ String replacement = switch (namespace ) {
91+ case "variable" -> "v." + member ;
92+ case "ctrl" -> "v.ctrl_" + member ;
93+ default -> namespace + "." + member ;
94+ };
95+ matcher .appendReplacement (output , Matcher .quoteReplacement (replacement ));
96+ }
97+ matcher .appendTail (output );
98+ return output .toString ();
99+ }
100+
101+ private String rewriteDynamicFunctionArguments (String source ) {
102+ Matcher secondOrder = SECOND_ORDER_CALL .matcher (source );
103+ StringBuffer output = new StringBuffer ();
104+ while (secondOrder .find ()) {
105+ int symbolId = symbols .idFor (secondOrder .group (1 ));
106+ String replacement = "ysm.second_order(" + symbolId + "," ;
107+ secondOrder .appendReplacement (output , Matcher .quoteReplacement (replacement ));
108+ }
109+ secondOrder .appendTail (output );
110+
111+ Matcher boneRotation = BONE_ROTATION_CALL .matcher (output .toString ());
112+ StringBuffer rewritten = new StringBuffer ();
113+ while (boneRotation .find ()) {
114+ int symbolId = symbols .idFor (boneRotation .group (1 ));
115+ String axis = boneRotation .group (2 ).toLowerCase (Locale .ROOT );
116+ String replacement = "ysm.bone_rot_" + axis + "(" + symbolId + ")" ;
117+ boneRotation .appendReplacement (rewritten , Matcher .quoteReplacement (replacement ));
118+ }
119+ boneRotation .appendTail (rewritten );
120+ return rewritten .toString ();
69121 }
70122}
0 commit comments