From ac981b37f18e6f02a41675e1db734abe829d882c Mon Sep 17 00:00:00 2001 From: DanTGL <33489389+DanTGL@users.noreply.github.com> Date: Mon, 29 Mar 2021 08:25:02 +0200 Subject: [PATCH 1/4] Added comma separated declarations to 'SET' --- doc/source/language/variables.rst | 5 +++ .../declaration/multi_declaration_test.ks | 8 +++++ src/kOS.Safe/Compilation/KS/Compiler.cs | 6 +++- src/kOS.Safe/Compilation/KS/Parser.cs | 32 +++++++++++++++++++ 4 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 kerboscript_tests/declaration/multi_declaration_test.ks diff --git a/doc/source/language/variables.rst b/doc/source/language/variables.rst index 7193add145..53a829433d 100644 --- a/doc/source/language/variables.rst +++ b/doc/source/language/variables.rst @@ -268,6 +268,11 @@ This follows the :ref:`scoping rules explained below `. If the variable can be found in the current local scope, or any scope higher up, then it won't be created and instead the existing one will be used. +It is also possible to set the values of multiple variables in a single ``SET`` statement +by separating the assignments with commas, as shown below:: + + SET X TO 1, Y TO 5, S TO "abc". + .. _unset: ``UNSET`` diff --git a/kerboscript_tests/declaration/multi_declaration_test.ks b/kerboscript_tests/declaration/multi_declaration_test.ks new file mode 100644 index 0000000000..6fd37b3a63 --- /dev/null +++ b/kerboscript_tests/declaration/multi_declaration_test.ks @@ -0,0 +1,8 @@ +// Tests comma-separated declarations of variables + +print("Testing with 'SET'"). +set a to 1, b to 2, c to "a". + +print " 1. The first variable has the correct value: " + (a = 1). +print " 2. The second variable has the correct value: " + (b = 2). +print " 3. The third variable has the correct value" + (c = "a"). diff --git a/src/kOS.Safe/Compilation/KS/Compiler.cs b/src/kOS.Safe/Compilation/KS/Compiler.cs index 4ad2e7012d..6b1d5bb34c 100644 --- a/src/kOS.Safe/Compilation/KS/Compiler.cs +++ b/src/kOS.Safe/Compilation/KS/Compiler.cs @@ -2175,7 +2175,11 @@ private ParseNode DepthFirstLeftSearch(ParseNode node, TokenType tokType) private void VisitSetStatement(ParseNode node) { NodeStartHousekeeping(node); - ProcessSetOperation(node.Nodes[1], node.Nodes[3]); + + for (int i = 1; i < node.Nodes.Count; i += 4) + { + ProcessSetOperation(node.Nodes[i], node.Nodes[i + 2]); + } } /// diff --git a/src/kOS.Safe/Compilation/KS/Parser.cs b/src/kOS.Safe/Compilation/KS/Parser.cs index 2dd1edfb98..6c98732386 100644 --- a/src/kOS.Safe/Compilation/KS/Parser.cs +++ b/src/kOS.Safe/Compilation/KS/Parser.cs @@ -453,6 +453,38 @@ private void Parseset_stmt(ParseNode parent) // NonTerminalSymbol: set_stmt // Concat Rule Parseexpr(node); // NonTerminal Rule: expr + // Concat Rule + tok = scanner.LookAhead(TokenType.COMMA); // ZeroOrMore Rule + while (tok.Type == TokenType.COMMA) + { + tok = scanner.Scan(TokenType.COMMA); // Terminal Rule: COMMA + n = node.CreateNode(tok, tok.ToString()); + node.Token.UpdateRange(tok); + node.Nodes.Add(n); + if (tok.Type != TokenType.COMMA) { + tree.Errors.Add(new ParseError("Unexpected token '" + tok.Text.Replace("\n", "") + "' found. Expected " + TokenType.COMMA.ToString(), 0x1001, tok)); + return; + } + + // Concat Rule + Parsevaridentifier(node); // NonTerminal Rule: varidentifier + + // Concat Rule + tok = scanner.Scan(TokenType.TO); // Terminal Rule: TO + n = node.CreateNode(tok, tok.ToString()); + node.Token.UpdateRange(tok); + node.Nodes.Add(n); + if (tok.Type != TokenType.TO) { + tree.Errors.Add(new ParseError("Unexpected token '" + tok.Text.Replace("\n", "") + "' found. Expected " + TokenType.TO.ToString(), 0x1001, tok)); + return; + } + + // Concat Rule + Parseexpr(node); // NonTerminal Rule: expr + + tok = scanner.LookAhead(TokenType.COMMA); // ZeroOrMore Rule + } + // Concat Rule tok = scanner.Scan(TokenType.EOI); // Terminal Rule: EOI n = node.CreateNode(tok, tok.ToString() ); From 87e9c021b0bae6cb53749932484577780d3649b2 Mon Sep 17 00:00:00 2001 From: DanTGL <33489389+DanTGL@users.noreply.github.com> Date: Tue, 22 Jun 2021 20:50:15 +0200 Subject: [PATCH 2/4] Modified regex for SET in kRISC.tpg --- src/kOS.Safe/Compilation/KS/Parser.cs | 9 +++++---- src/kOS.Safe/Compilation/KS/kRISC.tpg | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/kOS.Safe/Compilation/KS/Parser.cs b/src/kOS.Safe/Compilation/KS/Parser.cs index 6c98732386..587caa6114 100644 --- a/src/kOS.Safe/Compilation/KS/Parser.cs +++ b/src/kOS.Safe/Compilation/KS/Parser.cs @@ -457,8 +457,10 @@ private void Parseset_stmt(ParseNode parent) // NonTerminalSymbol: set_stmt tok = scanner.LookAhead(TokenType.COMMA); // ZeroOrMore Rule while (tok.Type == TokenType.COMMA) { + + // Concat Rule tok = scanner.Scan(TokenType.COMMA); // Terminal Rule: COMMA - n = node.CreateNode(tok, tok.ToString()); + n = node.CreateNode(tok, tok.ToString() ); node.Token.UpdateRange(tok); node.Nodes.Add(n); if (tok.Type != TokenType.COMMA) { @@ -471,7 +473,7 @@ private void Parseset_stmt(ParseNode parent) // NonTerminalSymbol: set_stmt // Concat Rule tok = scanner.Scan(TokenType.TO); // Terminal Rule: TO - n = node.CreateNode(tok, tok.ToString()); + n = node.CreateNode(tok, tok.ToString() ); node.Token.UpdateRange(tok); node.Nodes.Add(n); if (tok.Type != TokenType.TO) { @@ -481,8 +483,7 @@ private void Parseset_stmt(ParseNode parent) // NonTerminalSymbol: set_stmt // Concat Rule Parseexpr(node); // NonTerminal Rule: expr - - tok = scanner.LookAhead(TokenType.COMMA); // ZeroOrMore Rule + tok = scanner.LookAhead(TokenType.COMMA); // ZeroOrMore Rule } // Concat Rule diff --git a/src/kOS.Safe/Compilation/KS/kRISC.tpg b/src/kOS.Safe/Compilation/KS/kRISC.tpg index ec3d0c752e..6926a0f390 100644 --- a/src/kOS.Safe/Compilation/KS/kRISC.tpg +++ b/src/kOS.Safe/Compilation/KS/kRISC.tpg @@ -153,7 +153,7 @@ directive -> lazyglobal_directive; // Add to this list later if we ma // ------------ statements -------------------- empty_stmt -> EOI; -set_stmt -> SET varidentifier TO expr EOI; +set_stmt -> SET varidentifier TO expr (COMMA varidentifier TO expr)* EOI; if_stmt -> IF expr instruction EOI? (ELSE instruction EOI?)?; until_stmt -> UNTIL expr instruction EOI?; fromloop_stmt -> FROM instruction_block UNTIL expr STEP instruction_block DO instruction EOI?; From 1d1fff72059a07609de9d3c9dd9821160cc42c8e Mon Sep 17 00:00:00 2001 From: DanTGL <33489389+DanTGL@users.noreply.github.com> Date: Tue, 29 Jun 2021 17:16:55 +0200 Subject: [PATCH 3/4] Added comma-separated declarations to 'DECLARE' statement. --- .../declaration/multi_declaration_test.ks | 26 +++++++- src/kOS.Safe/Compilation/KS/Compiler.cs | 6 +- src/kOS.Safe/Compilation/KS/Parser.cs | 59 +++++++++++++++++++ src/kOS.Safe/Compilation/KS/kRISC.tpg | 2 +- 4 files changed, 88 insertions(+), 5 deletions(-) diff --git a/kerboscript_tests/declaration/multi_declaration_test.ks b/kerboscript_tests/declaration/multi_declaration_test.ks index 6fd37b3a63..fc89343b99 100644 --- a/kerboscript_tests/declaration/multi_declaration_test.ks +++ b/kerboscript_tests/declaration/multi_declaration_test.ks @@ -1,8 +1,30 @@ // Tests comma-separated declarations of variables -print("Testing with 'SET'"). +print "Testing with 'SET'". set a to 1, b to 2, c to "a". print " 1. The first variable has the correct value: " + (a = 1). print " 2. The second variable has the correct value: " + (b = 2). -print " 3. The third variable has the correct value" + (c = "a"). +print " 3. The third variable has the correct value: " + (c = "a"). + +print "Testing with 'GLOBAL'". +global d is 5, e to 2. + +print " 1. The first variable has the correct value: " + (d = 5). +print " 2. The second variable has the correct value: " + (e = 2). + +print "Testing with 'DECLARE'". + +declare f is 12, g to 1. + +print " 1. The first variable has the correct value: " + (f = 12). +print " 2. The second variable has the correct value: " + (g = 1). + + +print "Testing with 'DECLARE GLOBAL'". + +declare h is 7, i to 15, j to 3. + +print " 1. The first variable has the correct value: " + (h = 7). +print " 2. The second variable has the correct value: " + (i = 15). +print " 3. The thrid variable has the correct value: " + (j = 3). diff --git a/src/kOS.Safe/Compilation/KS/Compiler.cs b/src/kOS.Safe/Compilation/KS/Compiler.cs index 6b1d5bb34c..b938a39f21 100644 --- a/src/kOS.Safe/Compilation/KS/Compiler.cs +++ b/src/kOS.Safe/Compilation/KS/Compiler.cs @@ -2691,8 +2691,10 @@ private void VisitDeclareStatement(ParseNode node) // DECLARE [GLOBAL|LOCAL] identifier TO expr. if (lastSubNode.Token.Type == TokenType.declare_identifier_clause) { - VisitNode(lastSubNode.Nodes[2]); - AddOpcode(CreateAppropriateStoreCode(whereToStore, true, "$" + GetIdentifierText(lastSubNode.Nodes[0]))); + for (int i = 0; i < lastSubNode.Nodes.Count; i += 4) { + VisitNode(lastSubNode.Nodes[i + 2]); + AddOpcode(CreateAppropriateStoreCode(whereToStore, true, "$" + GetIdentifierText(lastSubNode.Nodes[i]))); + } } // If the declare statement is of the form: diff --git a/src/kOS.Safe/Compilation/KS/Parser.cs b/src/kOS.Safe/Compilation/KS/Parser.cs index 587caa6114..229133482f 100644 --- a/src/kOS.Safe/Compilation/KS/Parser.cs +++ b/src/kOS.Safe/Compilation/KS/Parser.cs @@ -1365,6 +1365,65 @@ private void Parsedeclare_identifier_clause(ParseNode parent) // NonTerminalSymb // Concat Rule Parseexpr(node); // NonTerminal Rule: expr + // Concat Rule + tok = scanner.LookAhead(TokenType.COMMA); // ZeroOrMore Rule + while (tok.Type == TokenType.COMMA) + { + + // Concat Rule + tok = scanner.Scan(TokenType.COMMA); // Terminal Rule: COMMA + n = node.CreateNode(tok, tok.ToString() ); + node.Token.UpdateRange(tok); + node.Nodes.Add(n); + if (tok.Type != TokenType.COMMA) { + tree.Errors.Add(new ParseError("Unexpected token '" + tok.Text.Replace("\n", "") + "' found. Expected " + TokenType.COMMA.ToString(), 0x1001, tok)); + return; + } + + // Concat Rule + tok = scanner.Scan(TokenType.IDENTIFIER); // Terminal Rule: IDENTIFIER + n = node.CreateNode(tok, tok.ToString() ); + node.Token.UpdateRange(tok); + node.Nodes.Add(n); + if (tok.Type != TokenType.IDENTIFIER) { + tree.Errors.Add(new ParseError("Unexpected token '" + tok.Text.Replace("\n", "") + "' found. Expected " + TokenType.IDENTIFIER.ToString(), 0x1001, tok)); + return; + } + + // Concat Rule + tok = scanner.LookAhead(TokenType.TO, TokenType.IS); // Choice Rule + switch (tok.Type) + { // Choice Rule + case TokenType.TO: + tok = scanner.Scan(TokenType.TO); // Terminal Rule: TO + n = node.CreateNode(tok, tok.ToString() ); + node.Token.UpdateRange(tok); + node.Nodes.Add(n); + if (tok.Type != TokenType.TO) { + tree.Errors.Add(new ParseError("Unexpected token '" + tok.Text.Replace("\n", "") + "' found. Expected " + TokenType.TO.ToString(), 0x1001, tok)); + return; + } + break; + case TokenType.IS: + tok = scanner.Scan(TokenType.IS); // Terminal Rule: IS + n = node.CreateNode(tok, tok.ToString() ); + node.Token.UpdateRange(tok); + node.Nodes.Add(n); + if (tok.Type != TokenType.IS) { + tree.Errors.Add(new ParseError("Unexpected token '" + tok.Text.Replace("\n", "") + "' found. Expected " + TokenType.IS.ToString(), 0x1001, tok)); + return; + } + break; + default: + tree.Errors.Add(new ParseError("Unexpected token '" + tok.Text.Replace("\n", "") + "' found. Expected TO or IS.", 0x0002, tok)); + break; + } // Choice Rule + + // Concat Rule + Parseexpr(node); // NonTerminal Rule: expr + tok = scanner.LookAhead(TokenType.COMMA); // ZeroOrMore Rule + } + // Concat Rule tok = scanner.Scan(TokenType.EOI); // Terminal Rule: EOI n = node.CreateNode(tok, tok.ToString() ); diff --git a/src/kOS.Safe/Compilation/KS/kRISC.tpg b/src/kOS.Safe/Compilation/KS/kRISC.tpg index 6926a0f390..c646ec3a95 100644 --- a/src/kOS.Safe/Compilation/KS/kRISC.tpg +++ b/src/kOS.Safe/Compilation/KS/kRISC.tpg @@ -172,7 +172,7 @@ remove_stmt -> REMOVE expr EOI; log_stmt -> LOG expr TO expr EOI; break_stmt -> BREAK EOI; preserve_stmt -> PRESERVE EOI; -declare_identifier_clause -> IDENTIFIER (TO|IS) expr EOI; +declare_identifier_clause -> IDENTIFIER (TO|IS) expr (COMMA IDENTIFIER (TO|IS) expr)* EOI; declare_parameter_clause -> PARAMETER IDENTIFIER ((TO|IS) expr)? (COMMA IDENTIFIER ((TO|IS) expr)?)* EOI; declare_function_clause -> FUNCTION IDENTIFIER instruction_block EOI?; declare_lock_clause -> LOCK IDENTIFIER TO expr EOI; From 2ba90213fc4977c2ce71a915b2ff3aeba0e731d2 Mon Sep 17 00:00:00 2001 From: DanTGL <33489389+DanTGL@users.noreply.github.com> Date: Sun, 18 Jul 2021 16:02:43 +0200 Subject: [PATCH 4/4] Updated docs with comma-separated declarations for 'DECLARE'. --- doc/source/language/variables.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/source/language/variables.rst b/doc/source/language/variables.rst index 53a829433d..feb99891ef 100644 --- a/doc/source/language/variables.rst +++ b/doc/source/language/variables.rst @@ -92,6 +92,18 @@ Any variable declared with ``DECLARE``, ``DECLARE LOCAL``, or ``LOCAL`` will only exist inside the code block section it was created in. After that code block is finished, the variable will no longer exist. +It is also possible to declare multiple variables in a single ``DECLARE`` statement, +separated by commas, as shown below:: + + // These all do the exact same thing - make local variables: + DECLARE A IS 5, B TO 1, C TO "O". + LOCAL A IS 5, B TO 1, C TO "O". + DECLARE LOCAL A IS 5, B TO 1, C TO "O". + + // These do the exact same thing - make global variables: + GLOBAL A IS 5, B TO 1, C TO "O". + DECLARE GLOBAL A IS 5, B TO 1, C TO "O". + See Scoping: ::::::::::::