4 files changed,
60 insertions(+),
1 deletions(-)
Author:
Oleksandr Smirnov
olexsmir@gmail.com
Committed at:
2025-10-17 13:56:03 +0300
Change ID:
nqyzqwsnkqplwzrwqxtnlmvtqxvssuzp
Parent:
35a5e15
jump to
| M | src/gbf/eval.gleam |
| M | src/gbf/lexer.gleam |
| M | src/gbf/parser.gleam |
| M | src/gbf/vm.gleam |
M
src/gbf/eval.gleam
@@ -7,10 +7,15 @@ import gleam/list
import gleam/result pub type Error { + /// An unexpected command was encountered at the given position. + UnexpectedCommand(pos: lexer.Position) + + /// An error occurred in the virtual machine VmError(reason: vm.Error) - UnexpectedCommand(pos: lexer.Position) } +/// Evaluates an AST node against the virtual machine. +/// pub fn eval(vm: VirtualMachine, node: AST) -> Result(VirtualMachine, Error) { case node { parser.Leaf(command) -> eval_command(command, vm)
M
src/gbf/lexer.gleam
@@ -8,6 +8,7 @@ Lexer(source: String, offset: Int, newlines: splitter.Splitter)
} pub type Position { + /// A token position in a wile, represented as offset of bytes Position(offset: Int) }
M
src/gbf/parser.gleam
@@ -5,7 +5,12 @@ import gleam/pair
import gleam/result pub type AST { + /// A single command + /// Leaf(Command) + + /// A block with nested children (used for loops) + /// Node(Block) }@@ -22,6 +27,12 @@ UnexpectedCommand
UnexpectedBlock } +/// Parses a list of tokens into an Abstract Syntax Tree. +/// +/// Takes a flat list of tokens with their positions and constructs +/// a hierarchical tree structure where loop blocks become nested nodes. +/// All tokens must be consumed for successful parsing. +/// pub fn parse(tokens: List(#(Token, Position))) -> Result(AST, Error) { let root = Node(Block(children: [], position: Position(0)))
M
src/gbf/vm.gleam
@@ -25,6 +25,7 @@ /// - A data cell is 8 bits, and an error will be reported if the program tries
/// to perform under- or overflow, i.e. decrement 0 or increment 255. /// - Two streams of bytes for input and output using the ASCII character /// encoding. +/// pub type VirtualMachine { VirtualMachine(pointer: Index, cells: Cells, output: String, input: List(Int)) }@@ -39,10 +40,19 @@ pub fn new(input: List(Int)) -> VirtualMachine {
VirtualMachine(input:, pointer: 0, cells: dict.new(), output: "") } +/// Returns the accumulated output string from the virtual machine. +/// pub fn output(vm: VirtualMachine) -> String { vm.output } +/// Gets the value of the cell at the specified pointer. +/// Returns an error if the pointer is out of bounds. +/// +/// ```gleam +/// get_cell(vm, 0) // Ok(0) +/// get_cell(vm, -1) // Error(PointerRanOffTape) +/// ``` pub fn get_cell(vm: VirtualMachine, pointer: Index) -> Result(Index, Error) { use pointer <- result.try(validate_tape_size(pointer))@@ -52,6 +62,16 @@ Error(_) -> Ok(0)
} } +/// Sets the value of the cell at the specified pointer. +/// +/// Returns an updated virtual machine if successful, or an error if: +/// - The pointer is out of bounds (< 0 or > 30,000) +/// - The value is out of bounds (< 0 or > 255) +/// +/// ```gleam +/// set_cell(vm, 0, 65) // Ok(...) +/// set_cell(vm, 0, 256) // Error(IntegerOverflow) +/// ``` pub fn set_cell( vm: VirtualMachine, pointer: Index,@@ -65,6 +85,13 @@ VirtualMachine(..vm, cells: new_cells)
|> Ok } +/// Moves the data pointer to the specified position. +/// Returns error if pointer is out of bounds. +/// +/// ```gleam +/// set_pointer(vm, 100) // Ok(...) +/// set_pointer(vm, -1) // Error(PointerRanOffTape) +/// ``` pub fn set_pointer( vm: VirtualMachine, pointer: Index,@@ -75,6 +102,16 @@ VirtualMachine(..vm, pointer:)
|> Ok } +/// Reads a byte from the input stream and stores it in the current cell. +/// +/// Consumes the first byte from the input list and writes it to the cell +/// at the current pointer position. +/// Returns an error if the input is empty. +/// +/// ```gleam +/// input_byte(vm) // Ok(...) +/// input_byte(empty_vm) // Error(EmptyInput) +/// ``` pub fn input_byte(vm: VirtualMachine) -> Result(VirtualMachine, Error) { case vm.input { [] -> Error(EmptyInput)@@ -87,6 +124,11 @@ }
} } +/// Reads the value from the current cell and appends it to the output as a character. +/// +/// Converts the cell value to an ASCII character and adds it to the output string. +/// Returns an error if the cell value is not a valid ASCII code point. +/// pub fn output_byte(vm: VirtualMachine) -> Result(VirtualMachine, Error) { use cell_value <- result.try(get_cell(vm, vm.pointer))