🌈 MOTO AUTOMATION & SCRIPTING SYSTEM
Introduction
Welcome to the :moto language specification! :moto is more than just a scripting language; it's a versatile tool designed to simplify and automate tasks across various environments and languages. With its motto centered on versatility and simplicity, :moto empowers developers to automate repetitive tasks and orchestrate complex workflows effortlessly.
Getting Started
Installation
To embark on your :moto journey, install the :moto CLI using your preferred package manager:
- Windows:
winget install moto.moto
- Mac:
brew install moto
- Linux:
sudo apt-get install moto
Language Syntax
Variables
Variables in :moto are declared using the let
keyword and can hold values of any type, determined at runtime.
let name = "John"
let age = 30
let isMarried = false
let hobbies = ["reading", "coding", "gaming"]
Tasks
Tasks are the core building blocks in :moto. They are defined with the task
keyword, followed by a name and code block. They can also be associated with specific runtimes.
task hello {
echo "Hello, $ENV{USER}!"
}:ps
Runtimes
Runtimes specify the language in which a task will be executed. They're defined using the :
operator followed by the runtime's name.
task hello {
echo "Hello, $ENV{USER}!"
}:ps
moto supports the following runtimes out of the box:
:js
for JavaScript
:dart
for Dart
:ps
for PowerShell
:py
for Python
:csharp
for C#
:rust
for Rust
but hey, you can add your own runtimes too! its as simple as defining a new runtime in the configuration file.
Blocks
Blocks in :moto, enclosed in curly braces {}
, allow you to encapsulate reusable sections of code or text.
block story {
Once upon a time, there was a small village. The villagers were afraid to go into the forest.
}
block story_book {
# the story of the village
[:story]
}
task read_story {
echo [:story_book]
}:ps
Cool Features
File Operations
:moto makes file operations a breeze. You can read, write, and manipulate files with ease using built-in functions like readFile
, writeFile
, and copyFile
.
let data = file.read("data.txt");
file.write("output.txt", data);
file.copy("data.txt", "backup.txt");
Networking
Interacting with APIs is simple with :moto. You can make HTTP requests, handle responses, and even authenticate using APIs seamlessly.
let response = http.get("https://api.example.com/data");
let data = response.body;
Conditional Execution
Execute tasks conditionally based on specific criteria using :moto's if
statement.
if (fileExists("data.txt")) {
processFile("data.txt")
} else {
echo "File does not exist"
}
Architecture Overview
1. Core Execution Engine
- Shell Runtime: Acts as the primary executor. All commands, regardless of the language, are funneled through this runtime for execution. This includes invoking compilers, interpreters, or any other toolchain components required by different languages.
- Command Execution: Leverages Rust's
Command
struct to execute shell or PowerShell commands. This could involve running scripts, compiling code, or invoking language-specific runtimes.
- Environment Setup: Before executing commands, the shell runtime can set up necessary environment variables, paths, or any prerequisites needed for the task.
2. Language-Specific Runtimes
- Definition: Each runtime, such as Dart, defines its execution environment, including the path to its executable, version information, and any specific flags or options needed.
- Integration with Shell Runtime: When a task requires execution in a language-specific runtime, it generates the appropriate shell commands (e.g., for compilation, execution) and sends these to the shell runtime for processing.
- Task Execution: Language-specific tasks, like building or testing code, are translated into shell commands respecting the runtime's configuration (paths, options, etc.).
3. Task and Variable Management
- Task Handling: The interpreter parses tasks from the script and, based on the runtime specified for each task, constructs and executes the corresponding shell commands.
- Variable Interpolation: Variables defined in the script can be interpolated into command strings before execution, allowing dynamic command generation based on script-defined variables.
4. Execution Flow
- Parse Script: The script is parsed into an AST, with clear distinctions between variables, tasks, runtimes, and blocks.
- Process Variables: Variables are evaluated and stored in a context accessible during task execution.
- Execute Tasks: For each task, determine the runtime (defaulting to shell if not specified) and generate the appropriate command string.
- Runtime Invocation: If a task specifies a non-shell runtime, translate the task into a shell command that invokes the appropriate language runtime (e.g., calling the Dart compiler or runtime with the correct parameters).
- Command Execution: Use Rust's
Command
struct to execute the generated shell command, handling stdout, stderr, and exit codes as required.
5. Error Handling and Logging
- Error Handling: Capture and handle errors from command execution, including non-zero exit codes, missing runtimes, and syntax errors in commands.
- Logging: Provide detailed logging for diagnostic purposes, including command execution details, errors, and warnings.
6. Modularity and Extensions
- Adding New Runtimes: To add support for a new language, define its runtime configuration and how to translate its tasks into shell commands.
- Customization: Allow users to customize environment setup, command options, and execution parameters through the script.