diff --git a/ros2rag.base/build.gradle b/ros2rag.base/build.gradle index 64d5ca773e495f54ebbce1a5cd372be52117df84..5cd8f595c7f2db045459e3e1ba4eda15fbbb58fc 100644 --- a/ros2rag.base/build.gradle +++ b/ros2rag.base/build.gradle @@ -74,23 +74,23 @@ task relast(type: JavaExec) { "--useJastAddNames", "--file", "--resolverHelper", - "--grammarName=./src/gen/jastadd/RelAST" + "--grammarName=./src/gen/jastadd/Ros2Rag" ] inputs.files file("../libs/relast.jar"), file("src/main/jastadd/RelAST.relast"), file("src/main/jastadd/Ros2Rag.relast") - outputs.files file("./src/gen/jastadd/RelAst.ast"), - file("src/gen/jastadd/RelAst.jadd"), - file("src/gen/jastadd/RelAstRefResolver.jadd"), - file('src/gen/jastadd/RelAstResolverStubs.jrag') + outputs.files file("./src/gen/jastadd/Ros2Rag.ast"), + file("src/gen/jastadd/Ros2Rag.jadd"), + file("src/gen/jastadd/Ros2RagRefResolver.jadd"), + file('src/gen/jastadd/Ros2RagResolverStubs.jrag') } jastadd { configureModuleBuild() modules { //noinspection GroovyAssignabilityCheck - module("RelAst") { + module("Ros2Rag") { java { basedir "." @@ -131,11 +131,11 @@ jastadd { } - module = "RelAst" + module = "Ros2Rag" astPackage = 'org.jastadd.ros2rag.ast' - parser.name = 'RelAstParser' + parser.name = 'Ros2RagParser' genDir = 'src/gen/java' diff --git a/ros2rag.base/src/main/jastadd/DumpTree.jrag b/ros2rag.base/src/main/jastadd/DumpTree.jrag index 0c119fd24a42983e26c16b9056611571a6e61f8a..4dd3985dc725e1f901499589ed1d471ca7ffa0ac 100644 --- a/ros2rag.base/src/main/jastadd/DumpTree.jrag +++ b/ros2rag.base/src/main/jastadd/DumpTree.jrag @@ -21,7 +21,7 @@ aspect DumpTree { } out.println(); String childIndent = indent + DUMP_TREE_INDENT; - for (ASTNode child : astChildren()) { + for (ASTNode<?> child : astChildren()) { if (child == null) { out.println(childIndent + "null"); } else { diff --git a/ros2rag.base/src/main/jastadd/NameResolution.jrag b/ros2rag.base/src/main/jastadd/NameResolution.jrag index ed0cbd6035364a52319986269807db5bcbbf6eb5..72b8522c24776e7b0ae57a5e03c998b0e3a92685 100644 --- a/ros2rag.base/src/main/jastadd/NameResolution.jrag +++ b/ros2rag.base/src/main/jastadd/NameResolution.jrag @@ -11,5 +11,31 @@ aspect NameResolution { throw new RuntimeException("TypeDecl " + name + " could not be resolved."); } + refine RefResolverStubs eq ASTNode.globallyResolveTokenComponentByToken(String id) { + // return a TokenComponent. id is of the form 'type_name + "." + token_name' + int dotIndex = id.indexOf("."); + String typeName = id.substring(0, dotIndex); + String tokenName = id.substring(dotIndex + 1); + TypeDecl type = program().resolveTypeDecl(typeName); + // iterate over components and find the matching tokenComponent + for (Component comp : type.getComponentList()) { + if (comp.isTokenComponent() && comp.getName().equals(tokenName)) { + return comp.asTokenComponent(); + } + } + System.err.println("Could not resolve TokenComponent '" + id + "'."); + return null; + } + + refine RefResolverStubs eq UpdateDefinition.resolveMappingByToken(String id) { + // return a MappingDefinition + for (MappingDefinition mappingDefinition : ros2rag().getMappingDefinitionList()) { + if (mappingDefinition.getID().equals(id)) { + return mappingDefinition; + } + } + System.err.println("Could not resolve MappingDefinition '" + id + "'."); + return null; + } } diff --git a/ros2rag.base/src/main/jastadd/Navigation.jrag b/ros2rag.base/src/main/jastadd/Navigation.jrag index b6028726b4406353f1acb0711d69ff66c509d661..4b233c249b6ec7441d70f2629d3179f138f49818 100644 --- a/ros2rag.base/src/main/jastadd/Navigation.jrag +++ b/ros2rag.base/src/main/jastadd/Navigation.jrag @@ -1,18 +1,27 @@ aspect Navigation { + // --- program --- inh Program ASTNode.program(); eq Program.getChild().program() = this; + eq Ros2Rag.getChild().program() = getProgram(); + // --- ros2rag + inh Ros2Rag ASTNode.ros2rag(); + eq Ros2Rag.getChild().ros2rag() = this; + + // --- typeDecls --- coll java.util.Set<TypeDecl> Program.typeDecls() [new java.util.HashSet<>()] root Program; TypeDecl contributes this to Program.typeDecls() for program(); + // --- relations --- coll java.util.Set<Relation> Program.relations() [new java.util.HashSet<>()] root Program; Relation contributes this to Program.relations() for program(); + // --- containingTypeDecl --- inh TypeDecl Component.containingTypeDecl(); eq TypeDecl.getChild().containingTypeDecl() = this; @@ -23,6 +32,15 @@ aspect Navigation { // syn boolean RelationComponent.multiplicityMany() = false; // eq ManyRelationComponent.multiplicityMany() = true; + // --- containedFile --- inh GrammarFile ASTNode.containedFile(); eq GrammarFile.getChild().containedFile() = this; + + // --- isTokenComponent --- + syn boolean Component.isTokenComponent() = false; + eq TokenComponent.isTokenComponent() = true; + + // --- asTokenComponent --- + syn TokenComponent Component.asTokenComponent() = null; + eq TokenComponent.asTokenComponent() = this; } diff --git a/ros2rag.base/src/main/jastadd/Ros2Rag.flex b/ros2rag.base/src/main/jastadd/Ros2Rag.flex index 9ef2f3e78e11730a94df503490e17971f2f7de6c..1c0d48d60120f5c5a0afbd62ef6f677f66f86124 100644 --- a/ros2rag.base/src/main/jastadd/Ros2Rag.flex +++ b/ros2rag.base/src/main/jastadd/Ros2Rag.flex @@ -1,18 +1,18 @@ package org.jastadd.ros2rag.scanner; -import org.jastadd.ros2rag.parser.RelAstParser.Terminals; +import org.jastadd.ros2rag.parser.Ros2RagParser.Terminals; %% %public %final -%class RelAstScanner +%class Ros2RagScanner %extends beaver.Scanner %type beaver.Symbol %function nextToken %yylexthrow beaver.Scanner.Exception -%scanerror RelAstScanner.ScannerError +%scanerror Ros2RagScanner.ScannerError %line %column @@ -40,11 +40,14 @@ TraditionalComment = [/][*][^*]*[*]+([^*/][^*]*[*]+)*[/] EndOfLineComment = "//" [^\n\r]* Comment = {TraditionalComment} | {EndOfLineComment} +MappingContent = [{][:][^:]*[:]+([^:}][^:]*[:]+)*[}] + ID = [a-zA-Z$_][a-zA-Z0-9$_]* %% {WhiteSpace} { /* ignore */ } {Comment} { return sym(Terminals.COMMENT); } +{MappingContent} { return sym(Terminals.MAPPING_CONTENT); } "abstract" { return sym(Terminals.ABSTRACT); } "rel" { return sym(Terminals.RELATION); } @@ -56,6 +59,7 @@ ID = [a-zA-Z$_][a-zA-Z0-9$_]* "maps" { return sym(Terminals.MAPS); } "to" { return sym(Terminals.TO); } "as" { return sym(Terminals.AS); } +"with" { return sym(Terminals.WITH); } ";" { return sym(Terminals.SCOL); } ":" { return sym(Terminals.COL); } @@ -67,8 +71,6 @@ ID = [a-zA-Z$_][a-zA-Z0-9$_]* ">" { return sym(Terminals.GT); } "[" { return sym(Terminals.LBRACKET); } "]" { return sym(Terminals.RBRACKET); } -"{" { return sym(Terminals.LB_CURLY); } -"}" { return sym(Terminals.RB_CURLY); } "/" { return sym(Terminals.SLASH); } "?" { return sym(Terminals.QUESTION_MARK); } "->" { return sym(Terminals.RIGHT); } diff --git a/ros2rag.base/src/main/jastadd/Ros2Rag.parser b/ros2rag.base/src/main/jastadd/Ros2Rag.parser index 44f276169549039cb0fee721ba50a589514194f8..9531cc51d88afd0792d4a7ec442fae30ef5e66d8 100644 --- a/ros2rag.base/src/main/jastadd/Ros2Rag.parser +++ b/ros2rag.base/src/main/jastadd/Ros2Rag.parser @@ -2,6 +2,7 @@ Ros2Rag ros2rag = update_definition.d ros2rag.r {: r.getUpdateDefinitionList().insertChild(d, 0); return r; :} | dependency_definition.d ros2rag.r {: r.getDependencyDefinitionList().insertChild(d, 0); return r; :} | mapping_definition.d ros2rag.r {: r.getMappingDefinitionList().insertChild(d, 0); return r; :} + | comment ros2rag.r {: return r; :} | {: return new Ros2Rag(); :} ; @@ -53,17 +54,43 @@ DependencyDefinition dependency_definition // y = IntPosition.of((int) p.getPositionX(), (int) p.getPositionY(), (int) p.getPositionZ()); //} MappingDefinition mapping_definition - = ID.id MAPS java_type_use.from_type ID.from_variable TO java_type_use.to_type ID.to_variable LB_CURLY mapping_def_content.content RB_CURLY + = ID.id MAPS mapping_type.from TO mapping_type.to MAPPING_CONTENT.content {: MappingDefinition result = new MappingDefinition(); result.setID(id); - result.setFrom(from_type); - result.setFromVariable(from_variable); - result.setTo(to_type); - result.setToVariable(to_variable); - result.setContent(content); + result.setFrom(from); + result.setTo(to); + result.setContent(content.substring(2, content.length() - 2)); return result; :} ; -String mapping_def_content = ID ; +MappingDefinitionType mapping_type + = java_type_use.type ID.variable + {: + MappingDefinitionType result = new MappingDefinitionType(); + result.setType(type); + result.setVariableName(variable); + return result; + :} + | java_type_use.type ID.variable WITH ID.method + {: + MappingDefinitionType result = new MappingDefinitionType(); + result.setType(type); + result.setVariableName(variable); + result.setSerializationMethodName(method); + return result; + :} +; + +//String mapping_def_content +// = LB_CURLY COL mapping_def_content_body.b {: return b.stream().collect(java.util.stream.Collectors.joining("\n")); :} +//; +// +//ArrayList mapping_def_content_body +// = COL RB_CURLY {: return new ArrayList(); :} +// | TEXT.text mapping_def_content_body.b {: b.add(0, text); return b; :} +//; +//String mapping_def_content +// = MappingContent.c {: int length = c.length(); return c.substring(2, length - 2); :} +//; diff --git a/ros2rag.base/src/main/jastadd/Ros2Rag.relast b/ros2rag.base/src/main/jastadd/Ros2Rag.relast index 6d13bd16b49fed7e9dddf94c0aab097ef46448ab..f730ea3ddf13de8bde9decbe350ec4abe7d79791 100644 --- a/ros2rag.base/src/main/jastadd/Ros2Rag.relast +++ b/ros2rag.base/src/main/jastadd/Ros2Rag.relast @@ -15,4 +15,5 @@ DependencyDefinition ::= <ID> ; rel DependencyDefinition.Source -> TokenComponent ; rel DependencyDefinition.Target -> TokenComponent ; -MappingDefinition ::= <ID> From:JavaTypeUse <FromVariable> To:JavaTypeUse <ToVariable> <Content> ; +MappingDefinition ::= <ID> From:MappingDefinitionType To:MappingDefinitionType <Content> ; +MappingDefinitionType ::= Type:JavaTypeUse <VariableName> <SerializationMethodName> ; // SerializationMethodName may be empty diff --git a/ros2rag.base/src/main/java/org/jastadd/ros2rag/compiler/Compiler.java b/ros2rag.base/src/main/java/org/jastadd/ros2rag/compiler/Compiler.java index fac820cfb3f29542ae78cfdfe5df54534390c57c..f5811f69ba65ecdc69452ad76b7796c7a1fae289 100644 --- a/ros2rag.base/src/main/java/org/jastadd/ros2rag/compiler/Compiler.java +++ b/ros2rag.base/src/main/java/org/jastadd/ros2rag/compiler/Compiler.java @@ -6,8 +6,8 @@ import org.jastadd.ros2rag.compiler.options.CommandLine; import org.jastadd.ros2rag.compiler.options.CommandLine.CommandLineException; import org.jastadd.ros2rag.compiler.options.Option; import org.jastadd.ros2rag.compiler.options.StringOption; -import org.jastadd.ros2rag.parser.RelAstParser; -import org.jastadd.ros2rag.scanner.RelAstScanner; +import org.jastadd.ros2rag.parser.Ros2RagParser; +import org.jastadd.ros2rag.scanner.Ros2RagScanner; import java.io.*; import java.nio.file.Files; @@ -24,10 +24,14 @@ public class Compiler { private ArrayList<Option<?>> options; private CommandLine commandLine; - public Compiler(String[] args) throws CommandLineException { + public Compiler() { options = new ArrayList<>(); addOptions(); + } + public int run(String[] args) throws CommandLineException, CompilerException { + options = new ArrayList<>(); + addOptions(); commandLine = new CommandLine(options); commandLine.parse(args); @@ -41,11 +45,11 @@ public class Compiler { printMessage("Running ROS2RAG Preprocessor"); if (!optionInputGrammar.isSet()) { - error("specify an input grammar"); + return error("specify an input grammar"); } if (!optionInputRos2Rag.isSet()) { - error("specify the ros2rag definition file"); + return error("specify the ros2rag definition file"); } List<String> otherArgs = commandLine.getArguments(); @@ -57,15 +61,16 @@ public class Compiler { printMessage("Writing output files"); writeToFile(outputDir + "/Grammar.relast", ros2Rag.getProgram().generateAbstractGrammar()); writeToFile(outputDir + "/ROS2RAG.jadd", ros2Rag.generateAspect()); + return 0; } - public static void main(String[] args) { + public static int main(String[] args) { try { - new Compiler(args); - } catch (CommandLineException e) { + return new Compiler().run(args); + } catch (CommandLineException | CompilerException e) { System.err.println(e.getMessage()); - System.exit(1); + return 1; } } @@ -73,14 +78,13 @@ public class Compiler { System.out.println(message); } - private void writeToFile(String filename, String str) { + private void writeToFile(String filename, String str) throws CompilerException { try { PrintWriter writer = new PrintWriter(filename); writer.print(str); writer.close(); } catch (Exception e) { - e.printStackTrace(); - System.exit(1); + throw new CompilerException("Could not write to file " + filename, e); } } @@ -95,37 +99,40 @@ public class Compiler { return option; } - private Ros2Rag parseProgram(String inputGrammarFileName, String inputRos2RagFileName) { + private Ros2Rag parseProgram(String inputGrammarFileName, String inputRos2RagFileName) throws CompilerException { Program program = new Program(); Ros2Rag ros2Rag; try (BufferedReader reader = Files.newBufferedReader(Paths.get(inputGrammarFileName))) { - RelAstScanner scanner = new RelAstScanner(reader); - RelAstParser parser = new RelAstParser(); + Ros2RagScanner scanner = new Ros2RagScanner(reader); + Ros2RagParser parser = new Ros2RagParser(); GrammarFile inputGrammar = (GrammarFile) parser.parse(scanner); + inputGrammar.dumpTree(System.out); program.addGrammarFile(inputGrammar); + inputGrammar.treeResolveAll(); } catch (IOException | Parser.Exception e) { - System.err.println(e.getMessage()); - System.exit(1); + throw new CompilerException("Could not parse grammar file " + inputGrammarFileName, e); } try (BufferedReader reader = Files.newBufferedReader(Paths.get(inputRos2RagFileName))) { - RelAstScanner scanner = new RelAstScanner(reader); - RelAstParser parser = new RelAstParser(); - ros2Rag = (Ros2Rag) parser.parse(scanner, RelAstParser.AltGoals.ros2rag); + Ros2RagScanner scanner = new Ros2RagScanner(reader); + Ros2RagParser parser = new Ros2RagParser(); + ros2Rag = (Ros2Rag) parser.parse(scanner, Ros2RagParser.AltGoals.ros2rag); ros2Rag.setProgram(program); } catch (IOException | Parser.Exception e) { - System.err.println(e.getMessage()); - System.exit(2); - return null; // poor compiler does not know System.exit() + throw new CompilerException("Could not parse ros2rag file " + inputRos2RagFileName, e); } + ros2Rag.dumpTree(System.out); + ros2Rag.treeResolveAll(); + ros2Rag.dumpTree(System.out); + return ros2Rag; } private void parse(Program program, Reader reader, String file) { - RelAstScanner scanner = new RelAstScanner(reader); - RelAstParser parser = new RelAstParser(); + Ros2RagScanner scanner = new Ros2RagScanner(reader); + Ros2RagParser parser = new Ros2RagParser(); try { GrammarFile newFile = (GrammarFile) parser.parse(scanner); @@ -139,13 +146,19 @@ public class Compiler { } } - protected void error(String message) { + protected int error(String message) { System.err.println("Error: " + message); System.err.println(); System.err.println("Usage: java -jar ros2rag.jar [--option1] [--option2=value] ... <filename1> <filename2> ... "); System.err.println("Options:"); System.err.print(commandLine.printOptionHelp()); - System.exit(1); + return 1; + } + + public static class CompilerException extends Exception { + CompilerException(String message, Throwable cause) { + super(message, cause); + } } } diff --git a/ros2rag.base/src/main/java/org/jastadd/ros2rag/compiler/SimpleMain.java b/ros2rag.base/src/main/java/org/jastadd/ros2rag/compiler/SimpleMain.java index 7d528acbd919ee2225ffd41bdb1b5dda41537dfe..a047453acf27229f169c4436b5a86025143125a3 100644 --- a/ros2rag.base/src/main/java/org/jastadd/ros2rag/compiler/SimpleMain.java +++ b/ros2rag.base/src/main/java/org/jastadd/ros2rag/compiler/SimpleMain.java @@ -2,8 +2,8 @@ package org.jastadd.ros2rag.compiler; import beaver.Parser; import org.jastadd.ros2rag.ast.*; -import org.jastadd.ros2rag.parser.RelAstParser; -import org.jastadd.ros2rag.scanner.RelAstScanner; +import org.jastadd.ros2rag.parser.Ros2RagParser; +import org.jastadd.ros2rag.scanner.Ros2RagScanner; import java.io.BufferedReader; import java.io.IOException; @@ -46,13 +46,13 @@ public class SimpleMain { r.getShouldUseLowSpeed().connectTo("/robot/config/speed"); */ Ros2Rag model = new Ros2Rag(); - Program program = parseProgram(Paths.get("src", "test", "resources", "MinimalExample.relast")); + Program program = parseProgram(Paths.get("src", "test", "resources", "Example.relast")); model.setProgram(program); MappingDefinition mappingDefinition = new MappingDefinition(); mappingDefinition.setID("PoseToPosition"); - mappingDefinition.setFrom(new SimpleJavaTypeUse("PBPose")); - mappingDefinition.setTo(new SimpleJavaTypeUse("Position")); + mappingDefinition.setFrom(makeMappingDefinitionType("PBPose", "x")); + mappingDefinition.setTo(makeMappingDefinitionType("Position", "y")); mappingDefinition.setContent(" pose.position.x += sqrt(.5 * size.x)\n" + " MAP round(2)\n" + " x = x / 100\n" + @@ -71,10 +71,17 @@ public class SimpleMain { System.out.println(model.generateAspect()); } + private static MappingDefinitionType makeMappingDefinitionType(String type, String variable) { + MappingDefinitionType result = new MappingDefinitionType(); + result.setType(new SimpleJavaTypeUse(type)); + result.setVariableName(variable); + return result; + } + private static Program parseProgram(Path path) { try (BufferedReader reader = Files.newBufferedReader(path)) { - RelAstScanner scanner = new RelAstScanner(reader); - RelAstParser parser = new RelAstParser(); + Ros2RagScanner scanner = new Ros2RagScanner(reader); + Ros2RagParser parser = new Ros2RagParser(); return (Program) parser.parse(scanner); } catch (IOException | Parser.Exception e) { e.printStackTrace(); diff --git a/ros2rag.base/src/test/java/org/jastadd/ros2rag/tests/RosToRagTest.java b/ros2rag.base/src/test/java/org/jastadd/ros2rag/tests/RosToRagTest.java index 19ad7e5bc85e6253c8dac1b421354c93b4519916..a70ea5246063b069cd114ea59e8d6ea734c9bf5f 100644 --- a/ros2rag.base/src/test/java/org/jastadd/ros2rag/tests/RosToRagTest.java +++ b/ros2rag.base/src/test/java/org/jastadd/ros2rag/tests/RosToRagTest.java @@ -6,12 +6,13 @@ import org.junit.jupiter.api.Test; import java.io.File; import java.nio.file.Paths; +import java.util.Objects; import static org.junit.jupiter.api.Assertions.assertTrue; public class RosToRagTest { - void transform(String inputGrammar, String inputRos2Rag, String outputDir) throws CommandLine.CommandLineException { + void transform(String inputGrammar, String inputRos2Rag, String outputDir) throws CommandLine.CommandLineException, Compiler.CompilerException { System.out.println(Paths.get(".").toAbsolutePath()); assertTrue(Paths.get(inputGrammar).toFile().exists(), "input grammar does not exist"); @@ -19,11 +20,11 @@ public class RosToRagTest { File outputDirFile = Paths.get(outputDir).toFile(); if (outputDirFile.exists()) { assertTrue(outputDirFile.isDirectory()); - if (outputDirFile.list().length != 0) { + if (Objects.requireNonNull(outputDirFile.list(), "Could not read output directory").length != 0) { System.out.println("output directory is not empty!"); } } else { - outputDirFile.mkdir(); + assertTrue(outputDirFile.mkdir()); } String[] args = { @@ -32,11 +33,11 @@ public class RosToRagTest { "--inputRos2Rag=" + inputRos2Rag }; - new Compiler(args); + new Compiler().run(args); } @Test - void transformMinimalExample() throws CommandLine.CommandLineException { + void transformMinimalExample() throws CommandLine.CommandLineException, Compiler.CompilerException { transform("src/test/resources/Example.relast", "src/test/resources/Example.ros2rag", "src/test/resources/out"); diff --git a/ros2rag.base/src/test/resources/Example.relast b/ros2rag.base/src/test/resources/Example.relast index f4b2aa014acd03fc3ea5f6bf06df84ab0757d7ab..aa17ad814128cf155d844e0f36f1114b1b1afa33 100644 --- a/ros2rag.base/src/test/resources/Example.relast +++ b/ros2rag.base/src/test/resources/Example.relast @@ -6,7 +6,7 @@ Zone ::= Coordinate* ; RobotArm ::= Joint* EndEffector <_AttributeTestSource:int> /<_AppropriateSpeed:double>/ ; // normally this would be: <AttributeTestSource:int> ; -Joint ::= <Name> <_CurrentPosition:IntPosition> ; // normally this would be: <CurrentPosition:IntPosition> +Joint ::= <Name> <CurrentPosition:IntPosition> ; // normally this would be: <CurrentPosition:IntPosition> EndEffector : Joint; diff --git a/ros2rag.base/src/test/resources/Example.ros2rag b/ros2rag.base/src/test/resources/Example.ros2rag index 26702ca21583f6fb90096bce86dec243e99d5d08..b2dd93dd6f275ce02e8f2c9ecaef08a72d941431 100644 --- a/ros2rag.base/src/test/resources/Example.ros2rag +++ b/ros2rag.base/src/test/resources/Example.ros2rag @@ -8,13 +8,14 @@ RobotArm._AppropriateSpeed canDependOn Joint.CurrentPosition as dependency1 ; RobotArm._AppropriateSpeed canDependOn RobotArm._AttributeTestSource as dependency2 ; // --- mapping definitions --- -LinkStateToIntPosition: map protobuf panda.Linkstate.PandaLinkState x to IntPosition y { +LinkStateToIntPosition maps panda.Linkstate.PandaLinkState x to IntPosition y {: panda.Linkstate.PandaLinkState.Position p = x.getPos(); + { int i = 0; } y = IntPosition.of((int) p.getPositionX(), (int) p.getPositionY(), (int) p.getPositionZ()); -} +:} -CreateSpeedMessage: map double x to protobuf config.Robotconfig.RobotConfig y { +CreateSpeedMessage maps double x to config.Robotconfig.RobotConfig y {: y = config.Robotconfig.RobotConfig.newBuilder() .setSpeed(x) .build(); -} +:}