@@ -28,64 +28,93 @@ public int process(List<ParseTree> list, int keywordPosition) throws ConfigCompi
2828 if (list .get (keywordPosition ).getData () instanceof CKeyword ) {
2929 // It's a lone keyword, so we expect some function to follow, which is the proc name + variables
3030 FileOptions options = list .get (keywordPosition ).getFileOptions ();
31+
32+ // Validate minimal required number of nodes.
3133 if (list .size () <= keywordPosition + 1 ) {
3234 throw new ConfigCompileException ("Unexpected keyword" , list .get (keywordPosition ).getTarget ());
3335 }
36+
37+ /*
38+ * Parse:
39+ * "proc _procName(params) { code }" to "proc(_procName, params, code)". Params and code are optional.
40+ * "proc _procName(params)" to "proc(_procName, params, noop())". Params are optional.
41+ * "proc _procName" to "get_proc(_procName)".
42+ */
3443 if (list .get (keywordPosition + 1 ).getData () instanceof CFunction ) {
44+
45+ // Create proc function node.
3546 ParseTree procNode = new ParseTree (new CFunction (
3647 DataHandling .proc .NAME , list .get (keywordPosition ).getTarget ()), options );
3748 procNode .getNodeModifiers ().merge (list .get (keywordPosition ).getNodeModifiers ());
49+
50+ // Add proc name to proc function node. Proc name node is currently a function node.
3851 procNode .addChild (new ParseTree (new CString (list .get (keywordPosition + 1 ).getData ().val (),
3952 list .get (keywordPosition + 1 ).getTarget ()), options ));
40- // Grab the functions children, and put them on the stack
53+
54+ // Move proc name function node children to proc function node.
4155 for (ParseTree child : list .get (keywordPosition + 1 ).getChildren ()) {
4256 procNode .addChild (child );
4357 }
44- boolean forwardDeclaration = false ;
45- if (list .size () > keywordPosition + 2 ) {
46- if (list .get (keywordPosition + 2 ).getData () instanceof CFunction cf
47- && com .laytonsmith .core .functions .Compiler .__cbrace__ .NAME .equals (cf .val ())) {
48- validateCodeBlock (list .get (keywordPosition + 2 ), "Expected braces to follow proc definition" );
49- procNode .addChild (getArgumentOrNoop (list .get (keywordPosition + 2 )));
50- } else {
51- // Forward declaration, add a noop "implementation"
52- forwardDeclaration = true ;
53- ParseTree statement = new ParseTree (new CFunction (Compiler .__statements__ .NAME , Target .UNKNOWN ),
54- list .get (keywordPosition + 1 ).getFileOptions (), true );
55- statement .addChild (new ParseTree (new CFunction (Meta .noop .NAME , Target .UNKNOWN ),
56- list .get (keywordPosition + 1 ).getFileOptions (), true ));
57- procNode .addChild (statement );
58- }
58+
59+ // Get code block from __cbrace__ function node. Define as forward declaration if code block is missing.
60+ if (list .size () > keywordPosition + 2
61+ && list .get (keywordPosition + 2 ).getData () instanceof CFunction cf
62+ && com .laytonsmith .core .functions .Compiler .__cbrace__ .NAME .equals (cf .val ())) {
63+
64+ // Validate code block and add to proc function node.
65+ validateCodeBlock (list .get (keywordPosition + 2 ), "Expected braces to follow proc definition" );
66+ procNode .addChild (getArgumentOrNoop (list .get (keywordPosition + 2 )));
67+
68+ // Remove processed nodes from AST.
69+ list .remove (keywordPosition ); // Remove keyword node.
70+ list .remove (keywordPosition ); // Remove proc name function node (with proc parameters).
71+ list .remove (keywordPosition ); // Remove __cbrace__ function node.
5972 } else {
60- throw new ConfigCompileException ("Expected braces to follow proc definition" , list .get (keywordPosition + 1 ).getTarget ());
61- }
62- list .remove (keywordPosition ); // Remove the keyword
63- list .remove (keywordPosition ); // Remove the function definition
64- if (!forwardDeclaration ) {
65- list .remove (keywordPosition ); // Remove the cbrace
73+
74+ // Define as forward declaration by add a "noop()" as code block.
75+ ParseTree statement = new ParseTree (new CFunction (Compiler .__statements__ .NAME , Target .UNKNOWN ),
76+ list .get (keywordPosition + 1 ).getFileOptions (), true );
77+ statement .addChild (new ParseTree (new CFunction (Meta .noop .NAME , Target .UNKNOWN ),
78+ list .get (keywordPosition + 1 ).getFileOptions (), true ));
79+ procNode .addChild (statement );
80+
81+ // Remove processed nodes from AST.
82+ list .remove (keywordPosition ); // Remove keyword node.
83+ list .remove (keywordPosition ); // Remove proc name function node (with proc parameters).
6684 }
67- list .add (keywordPosition , procNode ); // Add in the new proc definition
85+
86+ // Add proc function node to AST.
87+ list .add (keywordPosition , procNode );
88+
6889 } else if (list .get (keywordPosition + 1 ).getData () instanceof CBareString name ) {
69- // get_proc rewrite
70- list .remove (keywordPosition );
71- list .remove (keywordPosition );
90+
91+ // Parse "proc _procName" to "get_proc(_procName)".
92+ list .remove (keywordPosition ); // Remove keyword node.
93+ list .remove (keywordPosition ); // Remove proc name node.
94+
95+ // Add get_proc function node with proc name child node to AST.
7296 ParseTree getProc = new ParseTree (new CFunction (DataHandling .get_proc .NAME , Target .UNKNOWN ), options , true );
7397 getProc .addChild (new ParseTree (new CString (name .val (), name .getTarget ()), options ));
7498 list .add (keywordPosition , getProc );
99+
75100 } else {
101+
102+ // Proc keyword used incorrectly.
76103 throw new ConfigCompileException ("Unexpected use of \" proc\" keyword" , list .get (keywordPosition ).getTarget ());
77104 }
78105
79106 } else if (nodeIsProcFunction (list .get (keywordPosition ))) {
80- // It's the functional usage, possibly followed by a cbrace. If so, pull the cbrace in, and that's it
81- if (list .size () > keywordPosition + 1 ) {
82- if (isValidCodeBlock (list .get (keywordPosition + 1 ))) {
83- list .get (keywordPosition ).addChild (getArgumentOrNoop (list .get (keywordPosition + 1 )));
84- list .remove (keywordPosition + 1 );
85- }
107+
108+ // Parse "proc(_procName, params) { code }" to "proc(_procName, params, code)". Params are optional.
109+ if (list .size () > keywordPosition + 1 && isValidCodeBlock (list .get (keywordPosition + 1 ))) {
110+
111+ // Pull in __cbrace__ function node as proc function node code block.
112+ list .get (keywordPosition ).addChild (getArgumentOrNoop (list .get (keywordPosition + 1 )));
113+ list .remove (keywordPosition + 1 ); // Remove __cbrace__ function node.
86114 }
87115 } else {
88- // Random keyword in the middle of nowhere
116+
117+ // Random proc keyword in the middle of nowhere.
89118 throw new ConfigCompileException ("Unexpected use of \" proc\" keyword" , list .get (keywordPosition ).getTarget ());
90119 }
91120 return keywordPosition ;
0 commit comments