Program Parser v6

hard · compilers, parsing, types

Program Parser v6

Parse tokens into an AST for the v6 language (modules + type annotations).

Function signature

func Parse(tokens []Token) (*Program, error)

Parse mode (same as v5)

  • If first token is module, parse module mode and return all module declarations.
  • Otherwise parse implicit module main with all statements.
  • This check runs once at start and does not switch per token.

New syntax

let x: number = 1;
var y: array<number> = [1,2];
const f: fn(string, bool) -> string = "";

fn add(a: number, b: number) -> number { return a + b; }
fn mapIt(x: fn(number)->string) -> array<string> { return []; }

Grammar

program     -> moduleDecl* | stmts (implicit main)
moduleDecl  -> "module" IDENT "{" moduleItem* "}"
moduleItem  -> importStmt | exportDecl | stmt
importStmt  -> "import" IDENT ("as" IDENT)? ";"
exportDecl  -> "export" (fnDecl | varDecl)

fnDecl      -> "fn" IDENT "(" params? ")" "->" type block
params      -> param ("," param)*
param       -> IDENT ":" type

varDecl     -> ("let"|"var"|"const") IDENT (":" type)? ("=" expr)? ";"

stmt        -> varDecl
            | ifStmt
            | whileStmt
            | forStmt
            | breakStmt
            | continueStmt
            | returnStmt
            | block
            | fnDecl
            | assignOrExpr

forStmt     -> "for" "(" forInit? ";" expr? ";" forPost? ")" block
forInit     -> varDeclNoSemi | assignOrExprNoSemi
forPost     -> assignOrExprNoSemi

expr        -> or
or          -> and ("||" and)*
and         -> equality ("&&" equality)*
comparison  -> term (("<"|"<="|">"|">=") term)*
term        -> factor (("+"|"-") factor)*
factor      -> unary (("*"|"/") unary)*
unary       -> ("!"|"-") unary | postfix
postfix     -> primary (call | index | member)*

array       -> "[" (expr ("," expr)*)? "]"
map         -> "{" (pair ("," pair)*)? "}"
pair        -> expr ":" expr

Type grammar

type       -> simpleType | fnType
simpleType -> "number" | "bool" | "string" | "nil"
           | "array" "<" type ">"
           | "map" "<" type "," type ">"
fnType     -> "fn" "(" typeList? ")" "->" type

typeList   -> type ("," type)*

AST requirements

Use provided structs.

  • Stmt.TypeAnn when : annotation is present, else nil.
  • Stmt.ParamTypes aligned with Stmt.Params.
  • Stmt.ReturnType required for every parsed function.
  • Type tree populated with:
    • Elem for arrays,
    • Key / Value for map,
    • Params / Return for fn types.

Primitive token names for type parsing are number, bool, string, nil. Anything else is unknown type.

Behavioral rules

  1. Function declarations
  • Parse params first, then require -> and return type.
  • Missing return arrow or return type fails.
  1. Variable declarations
  • Parse optional type annotation after name.
  • parseVarDecl and parseVarDeclNoSemi both support optional : type.
  1. Type parser validity
  • array<T> accepts one nested type.
  • map<K,V> requires comma and two nested types.
  • fn(P) requires params list in parentheses and arrow+return.
  1. L-values and for-loop behavior
  • Assignment targets remain: identifier or index only.
  • for-init can still use typed declaration (let i: number = 0).
  1. Error expectations
  • keep errors for malformed separators and missing delimiters (<, ,, ->, ) etc.)
  • unknown/unsupported type names should fail at parse stage.

Before implementation

Use the module’s worked reconstruction and independent debugging lab to predict an intermediate artifact first. Preserve one failing counterexample while implementing the stated API. The lesson’s transfer task uses a fresh case after the guided trace.

Run tests to see results
No issues detected
    Join Discord