Skip to content

Latest commit

 

History

15 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

dodolang

A small interpreted language for scalar and vector arithmetic, written in Rust.

Dodolang is a tree-walking interpreter built the classic way — lexer → parser → AST → interpreter — with an interactive REPL as the only frontend. It is an early work-in-progress: scalars, vectors, arithmetic and print work; matrices, loops and error recovery are not finished yet (see Status).

Requirements

  • Rust 2018 edition toolchain (rustc + cargo), e.g. via rustup. Built and tested against stable 1.97.1.

Build and run

cargo build            # debug build
cargo build --release  # optimised build (opt-level 3)
cargo run              # start the REPL
cargo test             # run the lexer/parser unit tests

The build succeeds but is noisy — around 70 warnings, mostly unused imports and unused mut/borrows. cargo fix can clear most of them.

cargo run drops you straight into the REPL:

Dodolang!
>>> scalar x
>>> x = 21
>>> print x
Literal(21)

Each line is lexed, parsed and interpreted on its own — the interpreter keeps one Environment, so variables persist across lines for the life of the session. There is no script-file runner yet; the test file in the repo root is just a scratch snippet.

Exit with Ctrl-D (end of input) or Ctrl-C. Because the REPL reads from stdin, you can also pipe a script in and it will run to the end and exit:

printf 'scalar x\nx = 21\nprint x\n' | cargo run -q

Language

Declarations

Every variable must be declared before it is assigned. Declarations are one per line.

scalar x            # a single value
vector y[3]         # a vector of length 3, zero-filled
matrix z[2,2]       # a matrix (partially implemented, see Status)

Assignment

x = 21
y = {1, 2, 3}
y = {1 2 3}         # commas are optional in vector literals

Expressions

Integer literals (i128), variables, parentheses, unary minus and the four binary operators, with the usual precedence (* and / bind tighter than + and -):

x = (21 * 5) + 3 + (6 * 4)

Vector arithmetic is dispatched on operand types at evaluation time:

Expression Result Example
scalar + - * / scalar scalar 1 + 23
scalar * vector vector, scaled element-wise 2 * {1,2,3}{2,4,6}
vector / scalar vector, divided element-wise
vector * vector scalar — the dot product {1,2,3} * {4,5,6}32

Printing

print x
print 1 + 2
print y

print writes the evaluated AST node using its Debug representation, so print 1 + 2 prints Literal(3) rather than 3, and printing a vector yields Vector(Token { token_type: IDENT, val: "y" }, [1, 2, 3]). The evaluator and environment also emit tracing output of their own while they work — variable names, operand dumps, and stray markers like wtf and asd2. All of it is development leftovers rather than intended behaviour.

Grammar

The grammar the parser actually implements today:

program        → declaration* EOF
declaration    → scalarDecl | vectorDecl | matrixDecl | statement
scalarDecl     → "scalar" IDENT NEWLINE
vectorDecl     → "vector" IDENT "[" INT "]" NEWLINE
matrixDecl     → "matrix" IDENT "[" INT "," INT "]" NEWLINE
statement      → printStmt | exprStmt
printStmt      → "print" expression NEWLINE
exprStmt       → expression NEWLINE
expression     → assignment
assignment     → IDENT "=" assignment | addition
addition       → multiplication ( ( "+" | "-" ) multiplication )*
multiplication → unary ( ( "*" | "/" ) unary )*
unary          → ( "-" | "!" ) unary | primary
primary        → INT | IDENT | "(" expression ")" | vectorLiteral
vectorLiteral  → "{" INT ( ","? INT )* "}"

Statements are newline-terminated; there are no semicolons and no block syntax.

Project layout

src/
  main.rs                    entry point — starts the REPL
  core/
    lexer/
      lexer.rs               character scanner producing Tokens
      helper.rs              is_letter / is_digit predicates
    token/
      token.rs               Token, TokenType, keyword lookup
    ast/
      parser.rs              recursive-descent parser
      expr.rs                Expr node enum
      stmt.rs                Stmt node enum
      ast.rs                 Program wrapper
    dodo/
      repl.rs                read-lex-parse-interpret loop
      interpreter.rs         tree-walking evaluator
      environment.rs         variable storage (HashMap<String, Vec<i128>>)
      error_types.rs         DodoParseError and error reporting

Values are stored uniformly as Vec<i128> — a scalar is a one-element vector, and a value's length is what distinguishes the two when it is read back.

Status

Working: scalar and vector declarations, assignment, integer arithmetic with precedence and grouping, scalar/vector mixed arithmetic, the dot product, print, and a persistent REPL environment.

Not yet implemented:

  • Matrices. matrix z[2,2] parses and declares storage, but only allocates columns elements and no 2-D operations or nested {{...}} literals exist.
  • for loops. The keyword is lexed and Stmt::FOR is defined, but the parser branch is commented out.
  • Error handling. Errors are unwrapped rather than reported, so anything invalid panics and kills the session instead of printing a diagnostic and continuing: q = = 5 panics in parser.rs (primary returns Err, unary unwraps it), and reading an undeclared variable panics in interpreter.rs (Environment::get returns None). Assigning to an undeclared variable is silently ignored instead.
  • Vector + / - and comparison operators (<, >, ==, !=) — the tokens exist but no evaluation path does.
  • Comments, strings, functions. Tokens and AST variants are sketched in; nothing consumes them.

The ndarray and nalgebra dependencies are declared ahead of the matrix work and are not meaningfully used yet.

Tests

Unit tests live alongside the code in #[cfg(test)] modules — token-level tests in src/core/lexer/lexer.rs and a statement-parsing test in src/core/ast/parser.rs. cargo test currently runs 4 tests, all passing (one, ast::tests::basic_statements, is an empty placeholder). Several interpreter and parser tests are commented out pending the API changes that outdated them.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages