DevDocs
Table of Contents
- 1. The Flow Shell - Developer Documentation
- 1.1. Introduction
- 1.2. Modules
- 1.2.1. reporters
- 1.2.2. flowloop
- 1.2.3. interpreter
- 1.3. The Main Program Loop

All that is gold does not glitter,
Not all those who wander are lost;
The old that is strong does not wither,
Deep roots are not reached by the frost.
From the ashes a fire shall be woken,
A light from the shadows shall spring;
Renewed shall be blade that was broken,
The crownless again shall be king.
- J.R.R. Tolkien, The Fellowship of the Ring
Welcome, to the home page of Marko Štajgár
My Crafts & Projects -> flow -> documentation
1. The Flow Shell - Developer Documentation
1.1. Introduction
Rough idea of what the flow lifecycle looks like with links to the corresponding modules documented further down bellow:
- Inicialize and parse the cli args
- Based on the choice of execution mode (REPL or from file) chosen by the user go into eighter FlowLoopFile or FlowLoopRepl mode
- Load Input
- Run Input through Lexer
- Run FlowLexer output through FlowParser
- Run FlowParser output through Executer
- If the end of input or source file is encountered (0 bytes read) or
FlowState::Exit
state is returned from the Executer then break out of the program loop and exit, otherwise go to step 3.
1.2. Modules
The Flow Shell codebase is divided into several rust modules that work together to compose the main program loop. Below is an overview of the modules:
- reporters: Handles reporting functionalities.
- DebugModeReporter: Debugging functionalities.
- FlowErrorReporter: Error reporting mechanisms.
- FlowLoop: Manages the main execution loop.
- HistoryHandler: Manages command history.
- FlowLoopREPL: REPL functionalities for interactive execution.
- FlowLoopFile: Handles file-based execution.
- Interpreter: The core interpreter for executing commands.
- FlowLexer: Lexical analysis of input.
- FlowParser: Parsing of commands.
- Executer: Executes parsed commands.
1.2.1. reporters
Current location: ./src/reporters
1.2.1.1. Submodules
1.2.1.1.1. debugmodereporter
Current location: ./src/reporters/debugmodereporter
This submodule implements simple debug-mode reporting functions, printing enter/exit events and informational messages for instrumenting function calls.
Logs the entry of a function with its arguments.
Source: flowdebugmodereporter.rs
pub fn flow_debug_mode_function_enter( module_name: &str, function_name: &str, args: Vec<&str> ) -> ()
Arguments:
module_name: &str
- name of the module emitting the event.function_name: &str
- name of the function being entered.args: Vec<&str>
- vector of string slices representing the function arguments.
Behavior:
- Prints a header line:
FUNCTION_ENTER - module_name -> function_name -> with args:
- Iterates over `args`, printing each with its index.
Return type:
- Void
Logs the exit of a function with its return values.
Source: flowdebugmodereporter.rs
pub fn flow_debug_mode_function_exit( module_name: &str, function_name: &str, return_values: Vec<&str> ) -> ()
Arguments:
module_name: &str
- name of the module emitting the event.function_name: &str
- name of the function being exited.return_values: Vec<&str>
- vector of string slices for the return values.
Behavior:
- Prints a header line:
FUNCTION_EXIT - module_name -> function_name -> with return values:
- Iterates over
return_values
, printing each with its index.
Return type:
- Void
Logs an informational message during function execution.
Source: flowdebugmodereporter.rs
pub fn flow_debug_mode_function_info( module_name: &str, function_name: &str, message: &str ) -> ()
Arguments:
module_name: &str
- name of the module emitting the event.function_name: &str
- name of the function reporting info.message: &str
- informational message to print.
Behavior:
- Prints a single line:
INFO - module_name -> function_name -> with message: "message"
Return type:
- Void
1.2.1.1.2. flowerrorreporter
This source file implements error reporting by printing formatted error messages to standard error.
Reports an error with its location and message.
Source: flowerrorreporter.rs
pub fn flow_report_error( line: u32, width: u32, error_location: &str, message: &str ) -> ()
Arguments:
line: u32
- line number where the error occurred (1-based).width: u32
- character position within the line (0 indicates the entire line).error_location: &str
- identifier of the function or module reporting the error.message: &str
- error message to display.
Behavior:
- Prints to standard error in the format:
[line {line}, char {width}] Error: {error_location} \u2192 {message}
.
Return type:
- Void
1.2.2. flowloop
Current location: ./src/flowloop
This module serves as the main composer of the input reading and interpreting.
1.2.2.1. Submodules
1.2.2.1.1. historyhandler
Current location: ./src/flowloop/historyhandler
This source file implements the shells history-logging functionality. It tracks commands entered during runtime and appends them to a history file upon exit or when explicitly called.
Source: flowhistoryhandler.rs
#[derive(Debug)] pub struct ShellHistoryLogger { hist_file_location: PathBuf, runtime_shell_history: Vec<String>, }
Fields:
hist_file_location: PathBuf
- filesystem path to the history file (either from theHISTLOCATION
envar or defaulting to~/.flow_history
in the users home directory).runtime_shell_history: Vec<String>
- in memory buffer of commands entered during the current session.
Constructs a new `ShellHistoryLogger`, determining and creating the history file if needed.
Source: flowhistoryhandler.rs
pub fn new() -> Result<Self, String>
Arguments: None
Return type:
- Returns
Result<ShellHistoryLogger, String>
- Ok: a logger with
hist_file_location
set and emptyruntime_shell_history
. - Err: an error message if home directory lookup, file creation, or custom-path validation fails.
- Ok: a logger with
Behavior:
- Checks
HISTLOCATION
envar for a custom path. - If unset, uses
HOME
orUSERPROFILE
to derive~/.flow_history
and creates it if nonexistent. - If set but the file doesnt exist, returns an error.
Appends all buffered entries to the history file.
Source: flowhistoryhandler.rs
pub fn log_all_history(&mut self) -> Result<(), String>
Arguments:
&mut self
- mutable reference to the logger.
Return type:
- Returns
Result<(), String>
- Ok: entries successfully written.
- Err: formatted I/O error.
Behavior:
- Opens
self.hist_file_location
with append mode. - Iterates over
runtime_shell_history
, writing each entry on its own line.
Adds a new command to the inmemory history buffer.
Source: flowhistoryhandler.rs
pub fn update(&mut self, new_input: String) -> Result<(), String>
Arguments:
&mut self
- mutable reference to the logger.new_input: String
- the command string to record.
Return type:
- Returns
Result<(), String>
alwaysOk(())
, since in-memory push cannot fail.
Behavior: Pushes new_input
into runtime_shell_history
.
Flushes the buffered history to disk, intended for shell exit.
Source: flowhistoryhandler.rs
pub fn drop(&mut self) -> Result<(), String>
Arguments:
&mut self
- mutable reference to the logger.
Return type:
- Returns
Result<(), String>
- Ok: history successfully written.
- Err: formatted error.
Behavior: Calls log_all_history()
and propagates any error.
1.2.2.2. flowlooprepl
Current location: ./src/flowloop
This source file implements the REPL functionality of the shell. It reads user input, invokes the interpreter, logs history, and handles debug reporting.
1.2.2.2.1. Functions
Reads one line from a buffered reader after printing a prompt.
Source: flowlooprepl.rs
fn flow_read_line<R: BufRead>( reader: &mut R, prompt: &str, ) -> io::Result<Option<String>>
Arguments:
reader: &mut R
- mutable reference to a generic that implements BufRead.prompt: &str
- reference to the prompt string to print.
Return type:
- Returns
io::Result<Option<String>>
:Ok(Some(line))
with the input line (including newline).Ok(None)
on EOF.Err
on I/O failure.
Main loop of the shell REPL: reads input, interprets it, logs it to history, and exits on FlowState::Exit
.
Source: flowlooprepl.rs
pub fn flow_loop_repl( debug_mode: bool ) -> Result<(), String>
Arguments:
debug_mode: bool
- flag indicating whether debug mode is enabled.
Return type:
- Returns
Result<(), String>
:Ok(()
on normal exit.Err(String)
if errors occured.
Behavior:
- Determines prompt skin from
PS1
or defaults to"> "
. - Initializes `TypeEnv` and `ShellHistoryLogger`.
- Loops while `running` is true:
- Reads and trims input.
- Calls
flow_interpret
; setsrunning = false
onFlowState::Exit
. - Updates in-memory history buffer.
- After loop, calls
shell_history_logger.drop()
to persist history.
1.2.2.3. flowloopfile
Current location: ./src/flowloop
This source file implements file-based REPL functionality. It reads s-expressions and non-s-expressions from a source file, invokes the interpreter on each expression, supports debug reporting, and stops on errors or exit signals.
1.2.2.3.1. Structs
Accumulates tokens into complete expressions, handles comments, tracks nesting, and emits full expressions when ready.
Source: flowloopfile.rs
#[derive(Debug)] struct SourceExpressionLoader { line_number: u32, word_number: u32, expression: String, started_as_s_expression: bool, in_comment: bool, in_single_line_comment: bool, new_expression: bool, paren_count: i32, }
Fields:
line_number: u32
- current source-file line index (1-based).word_number: u32
- count of words processed in the current expression.expression: String
- accumulated tokens forming the current expression.started_as_s_expression: bool
- true if the expression began with (, indicating an s-expression.in_comment: bool
- true when inside any comment.in_single_line_comment: bool
- true when inside a ; comment until end of line.new_expression: bool
- true when no tokens have yet been added to the current expression.paren_count: i32
- nesting depth of parentheses for s-expressions.
1.2.2.3.2. Methods
Initializes a fresh loader with zeroed counters and empty state.
Source: flowloopfile.rs
fn new() -> Self
Arguments: None
Returns:
- A `SourceExpressionLoader` with all fields reset.
Resets the loader state to begin accumulating a new expression.
Source: flowloopfile.rs
fn clear_last_expression(&mut self)
Arguments:
&mut self
- mutable reference to the loader instance.
Behavior: Clears `expression`, resets flags (started_as_s_expression
, in_comment
, in_single_line_comment
, new_expression
), and sets paren_count
back to zero.
Processes a single whitespace-separated word, updating comment state, parentheses count, and expression buffer. Emits a complete expression when balanced.
Source: flowloopfile.rs
fn handle_load_word(&mut self, word: &str) -> Option<String>
Arguments:
&mut self
- mutable reference to the loader.word: &str
- the next token from the source.
Returns:
Some(String)
when a full expression is complete (either an s-expression with balanced parentheses or a non-s-expression at line end). Expression includes all tokens and spacing.None
otherwise.
Behavior:
- If `word` starts with `;`, enters single-line comment mode.
- If in any comment, ignores the rest of the word.
- Appends `word` to `expression` (with space if not
new_expression
), incrementsword_number
. - If `word` starts with `(`, sets or continues s-expression state and increments
paren_count
. - If `word` ends with `)`, decrements
paren_count
, when it returns to zero in an s-expression, returns the accumulated `expression` and clears.
Called at the end of each source line to emit expressions that did not start with parentheses. Also resets single-line comment state.
Source: flowloopfile.rs
fn line_end(&mut self) -> Option<String>
Arguments:
&mut self
- mutable reference to the loader.
Returns:
Some(String)
when `expression` is non-empty and not an s-expression, containing the full expression.None
otherwise.
Behavior:
- Increments
line_number
. - If in single-line comment, clears comment flags and returns `None`.
- If `expression` is non-empty and not an s-expression, returns it and clears state.
1.2.2.3.3. Functions
Reads and interprets expressions from a file until EOF, errors, or an `Exit` signal.
Source: flowloopfile.rs
pub fn flow_loop_file( path: &PathBuf, debug_mode: bool, ) -> io::Result<()>
Arguments:
path: &PathBuf
- filesystem path to the source file.debug_mode: bool
- enable debug reporting.
Return type:
Ok(())
on normal completion.Err(io::Error)
if file I/O fails.
Behavior:
- Emits debug-enter event if enabled.
- Opens the file at `path`, on error, reports via
flow_report_error
and returns the I/O error. - Wraps file in
BufReader
and initializesSourceExpressionLoader
and a freshTypeEnv
. - Iterates over each line:
a. Splits line into whitespace tokens.
b. For each `word`, calls
handle_load_word
, onSome(expression)
, emits debug-info and callsflow_interpret
, stopping ifExit
orErrorsOccured
. c. After tokens, callsline_end
, onSome(expression)
interprets. - After EOF, if any tokens remain, flush them.
1.2.3. interpreter
Current location: ./src/interpreter
Contains the source for the flow lisp language interpreter.
1.2.3.1. Submodules
1.2.3.1.1. flowlexer
Current location: ./src/interpreter/lexer
This source file implements the lexer for the shells interpreter. It splits input lines into tokens, classifies identifiers, integers, string literals, and parentheses, and supports debug tracing.
Represents the kinds of lexemes recognized by the lexer.
Source: flowlexer.rs
#[derive(Debug, Clone, PartialEq, Eq)] pub enum TokenType { LeftParen, // ( RightParen, // ) Identifier, StringLiteral, Integer, }
Fields:
LeftParen
- single-character `(`.RightParen
- single-character `)`.Identifier
- names and symbols not matching other types.StringLiteral
- text enclosed in double quotes.Integer
- sequences of ASCII digits.
Holds a lexeme with its type and source location.
Source: flowlexer.rs
#[derive(Debug, Clone, PartialEq)] pub struct Token { pub token_type: TokenType, pub lexeme: String, pub line_number: u32, pub token_start_number: u32, }
Fields:
token_type: TokenType
- kind of the token.lexeme: String
- the exact substring from the source line.line_number: u32
- 1-based line index where the token was found.token_start_number: u32
- 0-based character index of the tokens start.
Classifies a raw substring as `Identifier` or `Integer` and appends it to the token list.
Source: flowlexer.rs
fn push_identifier( tokens: &mut Vec<Token>, text: &str, line_number: u32, start: u32 ) -> ()
Arguments:
tokens: &mut Vec<Token>
- buffer to receive the new token.text: &str
- the substring to classify.line_number: u32
- source line number.start: u32
- character index of `text` start.
Behavior:
- If `text` is all ASCII digits, token type is `Integer`, otherwise `Identifier`.
- Creates and pushes a `Token` with the given location and lexeme.
Splits a line of source into a vector of `Token`, handling strings, comments, and grouping.
Source: flowlexer.rs
pub fn flow_tokenize( line: &str, line_number: u32, debug_mode: bool ) -> Vec<Token>
Arguments:
line: &str
- the raw source line.line_number: u32
- 1-based index of the line.debug_mode: bool
- if `true`, emits debug-enter and debug-exit events.
Return type:
Vec<Token>
a list of tokens extracted from `line`.
Behavior:
- Iterates over characters, maintaining state for:
in_string
for text inside `" "`.in_comment
andin_single_line_comment
for `;` comments.current
buffer accumulating identifier/number text.- Positions
string_start
andtoken_start
.
- On encountering delimiters, flushes
current
viapush_identifier
as needed, pushes single-char tokens, or enters/exits string/comment modes. - After the loop, flushes any remaining identifier/number token.
- Returns the token vector.
1.2.3.1.2. typeenv
Current location: ./src/interpreter/typeenv
This source file implements the type system and environment for the shell interpreter. It defines a `Type` enum for expression types, a scoped `TypeEnv` for bindings, and functions to check and record variable definitions.
Represents the inferred or annotated type of an expression.
Source: flowtypeenv.rs
#[derive(Debug, Clone, PartialEq)] pub enum Type { Integer(i64), // integer literal with its value Boolean(bool), // boolean literal String(String), // string literal Identifier(String), // user-defined identifier type Function(Vec<Type>, Box<Type>), // function: arg types and return type Alias(String), // alias name for another type Unknown, // runtime-inferred or undetermined type }
Variants:
Integer(i64)
- literal 64 bit integer value.Boolean(bool)
- literal boolean value.String(String)
- literal string data.Identifier(String)
- refers to a named type or variable.Function(Vec<Type>, Box<Type>)
- function type signature.Alias(String)
- named alias for another type.Unknown
- placeholder for types to be inferred at runtime.
Manages a stack of scopes mapping names to `Type`.
Source: typeenv.rs
#[derive(Debug)] pub struct TypeEnv { scopes: Vec<HashMap<String, Type>>, }
Fields:
scopes: Vec<HashMap<String, Type>>
- stack of hash maps for nested scopes.
Methods:
new()
- initializes with a single empty scope.enter_scope()
- pushes a new, inner scope.exit_scope()
- pops the current scope.insert(name: String, var_value: Type)
- bindsname
tovar_value
in the current scope.lookup(name: &str) -> Option<&Type>
- searches from innermost to outermost scope.
Validates an optional annotation against an inferred type and records the binding.
Source: typechecker.rs
pub fn handle_define_var( name: String, var_type: Option<Type>, value: Type, env: &mut TypeEnv, ) -> Result<(), String>
Arguments:
name: String
- variable name.var_type: Option<Type>
- optional user annotation.value: Type
- inferred type of the initializer.env: &mut TypeEnv
- environment to bind the variable.
Behavior:
- If
var_type
isSome(annot)
, ensuresvalue == annot
, returning an `Err` on mismatch. - Inserts the binding into the current scope.
- Returns
Ok(())
on success orErr(String)
.
Performs type inference and checking on an `Expression`.
Source: typechecker.rs
pub fn type_check( expr: &Expression, env: &mut TypeEnv ) -> Result<Type, String>
Arguments:
expr: &Expression
- AST node to check.env: &mut TypeEnv
- current type environment.
Behavior:
- For `Integer`, `StringLiteral`, and `Bool`, returns the corresponding `Type` variant.
- For
Identifier(name)
, looks up `name` in `env`, cloning and returning the bound `Type`, or `Err` if unbound. - Returns `Err` for unimplemented AST variants.
1.2.3.1.3. flowparser
Current location: ./src/interpreter/parser
This source file implements the parser for the shells interpreter. It consumes a token stream produced by the lexer, builds an abstract syntax tree (AST) of `Expression` nodes, and prepares constructs for type checking and evaluation. It handles literals, variable/environment/alias definitions, commands with piping and redirection, lists of expressions, and error recovery.
Represents the different kinds of expressions the parser recognizes.
Source: flowparser.rs
#[derive(Debug, Clone, PartialEq)] pub enum ExpressionType { // atoms Integer(i64), StringLiteral(String), Identifier(String), Bool(bool), // reserved keywords DefineVar { name: String, var_type: Option<Type>, // optional annotation, always inferred at runtime for now value: Box<Expression> }, DefineEnvar { name: String, value: Box<Expression>, }, DefineAlias { name: String, value: Box<Expression>, }, // for shell purposes Command { name: String, params: Vec<Expression>, pipe: Option<Box<Expression>>, redirect: Option<(RedirectionType, PathBuf)>, }, // represents a parsed file List(Vec<Expression>), // for partial evaluation and error aggregation Error(ErrorExp), Unknown, }
Variants:
Integer(i64)
- numeric literal.StringLiteral(String)
- text enclosed in quotes.Identifier(String)
- names, variable references, and symbols.Bool(bool)
- boolean literal (`true` or `false`).DefineVar
- variable definition with optional type annotation and initializer.DefineEnvar
- environment variable definition with initializer.DefineAlias
- alias definition for commands.Command
- shell command invocation, with parameters, optional pipe target, and optional redirection.List(Vec<Expression>)
- top-level sequence of expressionsError(ErrorExp)
- placeholder for a parse error, captures location and message.Unknown
- fallback for unrecognized constructs.
Specifies kinds of I/O redirection in a command.
Source: flowparser.rs
#[derive(Debug, Clone, PartialEq)] pub enum RedirectionType { Input, Output { append: bool, stderr: bool, stdin: bool, }, }
Variants:
Input
- `< file` redirect for stdin.Output
- `>` or `>>` or variants:- append: if true, use `>>`;
- stderr: if true, redirect stderr, use `2>`;
- stdin: if true, redirect stdin as well, use `&>`;
Categorizes the define-keyword forms.
Source: flowparser.rs
#[derive(Debug, Clone, PartialEq)] pub enum KeywordDefineType { Var, Envar, Alias, }
Variants:
Var
- define `var`.Envar
- define `envar`.Alias
- define `alias`.
Enumerates redirection keywords recognized during parsing.
Source: flowparser.rs
#[derive(Debug, Clone, PartialEq)] pub enum KeywordRedirectType { Input, Output, OutputAppend, OutputStderr, OutputCombined, }
Variants correspond to `<`, `>`, `>>`, `2>`, and `&>` syntax.
Higher-level classification for parser tokens corresponding to keywords.
Source: flowparser.rs
#[derive(Debug, Clone, PartialEq)] pub enum KeywordType { Define(KeywordDefineType), Command, Pipe, Redirect(KeywordRedirectType), }
Variants:
Define
- wraps a `KeywordDefineType`.Command
- invocation keyword.Pipe
- `|`.Redirect
- wraps a `KeywordRedirectType`.
Holds a parsed expression node and its source token for location tracking.
Source: flowparser.rs
#[derive(Debug, Clone, PartialEq)] pub struct Expression { pub exp_start_token: Option<Token>, pub exp_type: ExpressionType, }
Fields:
exp_start_token: Option<Token>
- the first token of this expression (for error reporting).exp_type: ExpressionType
- the actual AST node kind and data.
Captures information about a parse-time error as an expression.
Source: flowparser.rs
#[derive(Debug, Clone, PartialEq)] pub struct ErrorExp { pub token: Option<Token>, pub error_location: String, pub message: String, }
Fields:
token: Option<Token>
- the token where the error was detected (if available).error_location: String
- textual description of the error positionmessage: String
- human-readable error message.
First pass turns a flat &[Token]
slice into a nested Expression::List
structure, detecting parentheses depth and basic atom forms.
Source: flowparser.rs
fn parse_s_expression( tokens: &[Token], pos: usize, has_errors: &mut bool ) -> (Expression, usize)
Arguments:
tokens: &[Token]
- the token stream from the lexer.pos: usize
- current parse position in `tokens`.has_errors: &mut bool
- accumulates parse errors.
Behavior:
- On `LeftParen`, enters a loop to parse sub-expressions until a matching `RightParen`.
- Recursively calls itself for nested lists.
- Converts `Identifier`, `Integer`, and `StringLiteral` tokens into their respective `ExpressionType` variants
- Returns an `Expression` and the next token position.
- Reports errors for unexpected tokens, unclosed parentheses, and EOF.
Second pass: walks the raw Expression::List
, recognizes keywords, and invokes specialized parsers (`parse_define`, `preproc_parse_cmd`)
. It also checks variable bindings and expands nested lists.
Source: flowparser.rs
fn expand_parsed_s_expression( exp: Expression, keyword_type_map: &HashMap<&str, KeywordType>, type_env: &mut TypeEnv, has_errors: &mut bool, ) -> Expression
Arguments:
exp: Expression
- the raw AST fromparse_s_expression
.keyword_type_map: &HashMap<&str, KeywordType>
- maps symbols to parsing actions(define, command, pipe, redirect)
.type_env: &mut TypeEnv
- for checking that identifiers are defined.has_errors: &mut bool
- records any new errors.
Behavior:
- Propagates existing `Error` expressions unchanged.
- On
ExpressionType::List(items)
:- If the first element is a keyword identifier, dispatches to
parse_define
orpreproc_parse_cmd
. - Otherwise, ensures the identifier is defined in
type_env
or emits an error. - Recursively expands each element to produce a new `List`.
- If the first element is a keyword identifier, dispatches to
- Atoms
(`Integer`, `StringLiteral`, `Identifier`, `Bool`)
are returned as-is.
Parses a var/envar/alias definition S-expression into a corresponding `ExpressionType`.
Source: flowparser.rs
fn parse_define( items: Vec<Expression>, keyword_define_type: &KeywordDefineType, keyword_type_map: &HashMap<&str, KeywordType>, type_env: &mut TypeEnv, has_errors: &mut bool, ) -> Expression
Arguments:
items: Vec<Expression>
- the three-element list: (define-keyword name expr value expr).keyword_define_type: &KeywordDefineType
- which define form (Var, Envar, Alias).keyword_type_map: &HashMap<&str, KeywordType>
- lookup for nested expansions.type_env: &mut TypeEnv
- environment for type inference/checking.has_errors: &mut bool
- flag to record parse or type errors.
Behavior:
- Extracts and validates the identifier
- Recursively expands the value expression via
expand_parsed_s_expression
. - Depending on
keyword_define_type
, constructs one of the correspondingExpressionType
. - Returns an
Expression
withexp_start_token
from the keyword and the chosenExpressionType
.
Processes a flat list of expressions into a shell `Command` AST node, handling parameters, piping, and redirection.
Source: flowparser.rs
fn parse_cmd( items: &Vec<Expression>, index: usize, keyword_type_map: &HashMap<&str, KeywordType>, type_env: &mut TypeEnv, has_errors: &mut bool, ) -> Expression
Arguments:
items: &Vec<Expression>
- sequence of expanded subexpressions.index: usize
- start index of the command name in `items`.keyword_type_map: &HashMap<&str, KeywordType>
- kind of database that matches `keyword` to its `KeywordType`.type_env: &mut TypeEnv
- for type checks of parameters.has_errors: &mut bool
- accumulates any errors encountered.
Behavior:
- Validates the command name is an `Identifier`.
- Iterates over subsequent `items`, distinguishing:
- Pipe tokens: recursing to parse the next command into `pipe`.
- Redirection keywords: recording a `RedirectionType` and expecting the next token as a path.
- Other expressions, expanded via
expand_parsed_s_expression
, collected into `params`.
- Reports errors
- Constructs
ExpressionType::Command { name, params, pipe, redirect }
.
Initial wrapper that validates the S-expression for a command and invokes parse_cmd
.
Source: flowparser.rs
fn preproc_parse_cmd( raw_items: Vec<Expression>, keyword_type_map: &HashMap<&str, KeywordType>, type_env: &mut TypeEnv, has_errors: &mut bool, ) -> Expression
Arguments:
raw_items: Vec<Expression>
- top-level S-expression whereraw_items[1]
should be a `List`.keyword_type_map: &HashMap<&str, KeywordType>
- kind of database that matches `keyword` to its `KeywordType`.type_env: &mut TypeEnv
- lookup for nested expansions.has_errors: &mut bool
- flag to record parse or type errors.
Behavior:
- Confirms
raw_items
contains at least two elements and thatraw_items[1]
isExpressionType::List
. - Extracts the inner
Vec<Expression>
and validates it is non-empty. - Delegates to
parse_cmd
with that vector starting at index `0`. - Returns an
Error
expression on invalid structure or command list.
Top-level entry: orchestrates token-to-AST conversion, error collection, and optional debug tracing.
Source: flowparser.rs
pub fn flow_parse( tokens: &[Token], type_env: &mut TypeEnv, debug_mode: bool, ) -> (Expression, bool) { \u2026 }
Arguments:
tokens: &[Token]
- input token stream.type_env: &mut TypeEnv
- initial type environment.debug_mode: bool
- if `true`, emits enter/exit debug events.
Behavior:
- Builds a
keyword_map
of reserved words. - Calls
parse_s_expression
to get raw AST and updateshas_errors
. - Calls
expand_parsed_s_expression
to produce the final AST, dispatching to specialized parsers. - Returns the final `Expression` and
has_errors
flag.
1.2.3.1.4. executer
Current location: ./src/interpreter/executer
This source file implements the runtime execution engine: launching processes, managing pipelines, built-in commands, error reporting, glob expansion, redirections, and evaluation via `FlowState`.
Current location: ./src/interpreter/executer/builtincommands
This source file implements detection and execution of built-in shell commands for the interpreter.
Identifies the supported built-in commands.
Source: flowbuiltincommands.rs
#[derive(PartialEq, Clone)] pub enum BuiltInCommandType { Exit, // exit the shell Help, // display help text ChangeDir, // cd <dir> None, // not a built-in }
Variants:
Exit
- terminate the shell loop.Help
- show usage information.ChangeDir
- change the current working directory.None
- indicates the command is not built-in.
Maps a command name to its `BuiltInCommandType`.
Source: flowbuiltincommands.rs
pub fn is_built_in_command(name: &String) -> BuiltInCommandType { match name.to_lowercase().as_str() { "exit" => BuiltInCommandType::Exit, "help" => BuiltInCommandType::Help, "cd" => BuiltInCommandType::ChangeDir, _ => BuiltInCommandType::None, } }
Arguments:
name: &String
- command name string (case-insensitive).
Behavior: Returns the corresponding `BuiltInCommandType`.
Executes the specified built-in command with given parameters.
Source: flowbuiltincommands.rs
pub fn execute_built_in_command( kind: &BuiltInCommandType, params: Vec<String>, ) -> Result<(), String>
Arguments:
kind: &BuiltInCommandType
- which built-in to run.params: Vec<String>
- command arguments.
Behavior:
- Exit: returns
Ok(())
, caller interprets this as an exit signal. - Help: prints help text to stdout.
- ChangeDir: expects one parameter, the target directory; calls
env::set_current_dir
. - None: does nothing and returns
Ok(())
.
Differentiates shell-loop control flow and error handling.
Source: flowexecuter.rs
// differentiate shell-loop states pub enum FlowState { FreeToMove, ErrorsOccured, Return(Type), Error { message: String, exp: Option<Expression>, }, Exit, }
Variants:
FreeToMove
- ready for the next command.ErrorsOccured
- one or more errors have occurred, skip to error handler.Return(Type)
- a return from a function or script, carrying its TypeError { message, exp }
- runtime error with a message and optional Expression reference.Exit
- terminate the shell loop and exit.
Recursively reports all parse-time errors in an AST.
Source: flowexecuter.rs
fn report_all_parse_errors( parsed_exp: Expression, ) -> ()
Arguments:
parsed_exp: Expression
- AST to inspect.
Behavior:
- On
ExpressionType::Error(err)
, extracts line, column, location, and message then callsflow_report_error
. - On
ExpressionType::List(items)
, recurses into each sub-expression. - Ignores other.
Performs filesystem globbing on command arguments.
Source: flowexecuter.rs
fn expand_globs( args: Vec<String> ) -> Result<Vec<String>, String>
Arguments:
args: Vec<String>
- raw argument strings.
Behavior:
- For each argument containing `*`, `?`, or `[`, uses
glob(&arg)
. - On matches, adds each paths string form.
- Returns
Ok(expanded_args)
on success.
Forks and executes an external command with redirection and optional piping.
Source: flowexecuter.rs
fn execute_command( name: &str, params: Vec<String>, redirect_stderr: Option<PathBuf>, redirect_stdout: Option<PathBuf>, redirect_stdin: Option<PathBuf>, mut prev_pipe_output: Option<Stdio>, pipe_stdout: bool, ) -> Result<io::Result<Child>, String>
Arguments:
name: &str
- program to run.params: Vec<String>
- command-line arguments.redirect_stderr: Option<PathBuf>
- file for stderr.redirect_stdout: Option<PathBuf>
- file for stdout.redirect_stdin: Option<PathBuf>
- file for stdin.prev_pipe_output: Option<Stdio>
- upstream pipe as stdin.pipe_stdout: bool
- whether to pipe this processs stdout.
Behavior:
- Constructs
Command::new(name)
. - Sets up `stdin`, `stdout`, `stderr` based on redirection or piping.
- Appends arguments and spawns the child process.
- Returns nested `Result` to distinguish io errors and spawn errors.
Evaluates and executes a shell command AST node, handling built-ins, glob expansion, redirection, and pipelines.
Source: flowexecuter.rs
fn handle_command_execution( name: String, raw_params: Vec<String>, raw_redirect: Option<(RedirectionType, PathBuf)>, mut prev_pipe_output: Option<Stdio>, next_pipe: Option<Box<Expression>>, type_env: &mut TypeEnv, ) -> FlowState
Arguments:
name: String
- command identifier.raw_params: Vec<String>
- unexpanded argument patterns.raw_redirect: Option<(RedirectionType, PathBuf)>
- optional redirection.prev_pipe_output: Option<Stdio>
- pipe input from previous command.next_pipe: Option<Box<Expression>>
- AST for next piped command.type_env: &mut TypeEnv
- environment for var/envar lookup.
Behavior:
- Calls
expand_globs
. - Detects built-in commands via
is_built_in_command
, dispatches toexecute_built_in_command
. - Parses
raw_redirect
into separate stdin/stdout/stderr paths, errors on conflicts. - Invokes
execute_command
, checks spawn and I/O errors - If
next_pipe
exists, capture stdout, evaluate its parameters, and recurses intohandle_command_execution
. - On success of command, returns
FlowState::FreeToMove
.
Recursively evaluates any `Expression`, returning a `FlowState`.
Source: flowexecuter.rs
fn eval_expression( parsed_exp: Expression, type_env: &mut TypeEnv, ) -> FlowState
Arguments:
parsed_exp: Expression
- AST node to evaluate.type_env: &mut TypeEnv
- for variable and type lookups.
Behavior:
- Evaluates based on
ExpressionType
. - Propagates errors as
FlowState::Error
.
Top-level entry: tokenizes, parses, reports errors, and evaluates a single input line.
Source: flowexecuter.rs
pub fn flow_interpret( line: &str, line_number: u32, type_env: &mut TypeEnv, debug_mode: bool ) -> FlowState
Arguments:
line: &str
- raw input text.line_number: u32
- for error reporting.type_env: &mut TypeEnv
- current type environment.debug_mode: bool
- toggles debug tracing.
Behavior:
- Ignores lines starting with `;` (commends).
- Wraps non-parenthesized lines into
(exec ({line}))
form. - Tokenizes via
flow_tokenize
, parses withflow_parse
. - On parse errors, calls
report_all_parse_errors
and returnsErrorsOccured
. - Otherwise, calls
eval_expression
, reports runtime errors. - Returns the resulting `FlowState`.
1.3. The Main Program Loop
1.3.0.0.1. main
Current location: ./src/
This source implements the shells startup lifecycle: argument parsing, .flowrc
loading, interactive REPL, option to execute from a script.
The main function drives the shell through four phases:
- CLI argument processing
- RC configuration file handling
- Script file execution (if any)
- REPL invocation otherwise
Entry point. Coordinates all phases of the shell lifecycle.
Source: main.rs
fn main()
Arguments: None - reads from environment and CLI.
Behavior:
- Parses CLI flags and file paths into local variables.
- Ensures the RC file exists, creating it if necessary.
- Loads and executes the RC file via flowloopfile.
- If script files were passed, runs each via flowloopfile in the order that they came in.
- Otherwise, starts the interactive REPL via flowlooprepl.