Skip to content

vipulbhj/WasmBasic

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

WasmBasic

A small BASIC-like language compiler written in Rust. The compiler parses source code with chumsky, lowers it into a simple AST, emits WebAssembly with wasm-encoder, and can run the generated module either in the browser or through a native Wasmtime demo.

WasmBASIC

Project Layout

  • src/ast.rs: AST definitions for statements and expressions.
  • src/parser.rs: source parser and parser regression tests.
  • src/compiler.rs: semantic checks, WebAssembly emission, and compiler regression tests.
  • src/lib.rs: wasm-bindgen entry point used by the browser UI.
  • src/main.rs: native Wasmtime demo behind the native Cargo feature.
  • index.html and script.js: simple browser editor and output pane.

Running

Run the native demo:

cargo run --features native

Run tests:

cargo test

Check the default build:

cargo check

Build the browser package with wasm-pack:

wasm-pack build --target web

This will generate ./pkg, and contains WASM artifacts. I am currently manually copy-pasting wasm_basic.js and other assets to the root directory for the playground to work on github pages.

Language Specification

The language is an integer-only, statement-oriented BASIC-style language. Programs compile to a WebAssembly module with a start function; running the module executes the program immediately.

Lexical Rules

Keywords are uppercase and case-sensitive: LET, PRINT, IF, THEN, FOR, TO, and END.

Identifiers use Chumsky's ASCII identifier parser: ASCII letters, digits, and underscores, with the usual identifier start-character restrictions. Identifiers are case-sensitive, so A and a are different names.

Integer literals are base-10 signed 32-bit values in the compiler output. The parser currently accepts unsigned decimal literal syntax; negative values can be produced with subtraction expressions such as 0 - 1.

Spaces, tabs, and carriage returns are ignored between tokens. Newlines and semicolons separate statements. Multiple separators are allowed, so blank lines and repeated semicolons are valid.

Comments are not currently supported.

Program Structure

A program is a sequence of statements:

LET A = 10
A = A + 1
PRINT A

Statements may be separated with newlines:

LET A = 1
PRINT A

or semicolons:

LET A = 1; PRINT A;

Leading separators, trailing separators, and blank lines are allowed.

Variables

LET declares a new variable:

LET TOTAL = 0

Declarations are source-order checked. A variable must be declared before it is assigned or read. Redeclaring a name is a compiler error:

LET A = 1
LET A = 2

Use bare assignment to update an existing variable:

LET A = 1
A = A + 1

Assignments do not declare variables. This is a compiler error:

A = 1

There is no block-local scope yet. Names declared inside IF or FOR bodies reserve names in the same program-wide namespace, so another LET or loop variable with the same name is rejected.

Expressions

Expressions are integer expressions.

Supported atoms:

  • Integer literal: 123
  • Variable reference: A
  • Parenthesized expression: (A + 1)

Supported arithmetic operators:

  • +: addition
  • -: subtraction
  • *: multiplication
  • /: signed integer division
  • %: signed integer remainder

Precedence, from strongest to weakest:

  1. Parentheses
  2. *, /, %
  3. +, -

Operators are left-associative:

LET A = 10 - 3 - 2

is parsed as:

(10 - 3) - 2

Unary operators are not supported yet.

Printing

PRINT evaluates an expression and passes the resulting i32 to the imported WebAssembly function env.print:

PRINT A + 1

In the native demo, env.print maps to println!("{}", x). In the browser UI, it appends the printed value to the output pane.

If Statements

IF conditionally executes a block:

IF A < B THEN
    PRINT A
END

Supported comparison operators:

  • <: signed less-than
  • >: signed greater-than
  • ==: equality

The condition syntax is:

IF <expression> <comparison-operator> <expression> THEN
    <statements>
END

ELSE is not supported yet. Nested IF statements are supported.

For Loops

FOR repeats a block over an inclusive integer range:

FOR I = 1 TO 5
    PRINT I
END

The loop variable is declared by the FOR statement and must not conflict with any existing name. The current compiler requires both bounds to be integer literals:

FOR I = 0 TO 3
    PRINT I
END

This is rejected for now, even though the parser accepts the syntax:

LET END_VALUE = 3
FOR I = 0 TO END_VALUE
    PRINT I
END

Loop ranges are inclusive. If the start literal is greater than the end literal, the loop emits no body executions. Loops are currently unrolled at compile time instead of emitted as WebAssembly loop instructions.

Blocks and Separators

Blocks are statement lists terminated by END. Blank lines are valid inside blocks and before END:

FOR I = 1 TO 2

    IF I < 2 THEN

        PRINT I

    END

END

Compiler Errors

The compiler reports semantic errors before emitting Wasm. Current compile-time errors include:

  • Duplicate declarations: LET A = 1 followed by LET A = 2
  • Duplicate loop/declaration names: LET I = 0 followed by FOR I = 1 TO 3
  • Assignment before declaration: A = 1
  • Reading an undeclared variable: PRINT A
  • Non-literal FOR bounds in the current compiler

WebAssembly ABI

The emitted module imports one function:

env.print: (i32) -> ()

The generated program function is exported as the module start function, so instantiating the module runs the program immediately. There are no exported user functions.

Unsupported Features

These are not part of the current language:

  • Strings
  • Comments
  • Functions or RETURN
  • Arrays
  • INPUT
  • ELSE
  • WHILE
  • User-defined procedures
  • Floating point numbers
  • Boolean literals
  • Unary minus or unary plus

About

A compiler written in Rust for a small TinyBASIC inspired language, in parser-combinator over WASM backend.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors