Help us shape the future of Go! Take the 2026 Go Developer Survey

parser

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 21, 2026 License: BSD-3-Clause Imports: 7 Imported by: 6

README

go-ruby-parser/parser

parser — go-ruby-parser

ci License Go

A pure-Go (CGO=0) Ruby front-end — a lexer, a recursive-descent + Pratt parser, and an AST for Ruby source. No cgo, no Prism, no shelling out to Ruby: the single thing the Go ecosystem lacked for building Ruby tooling (linters, formatters, analysers, doc generators, LSP servers, transpilers) in pure Go.

It was extracted from the go-embedded-ruby interpreter — which now consumes it — and is developed test-first against MRI Ruby 4.0.5.

Install

go get github.com/go-ruby-parser/parser

Usage

import "github.com/go-ruby-parser/parser"

prog, err := parser.Parse(`
def fib(n)
  n < 2 ? n : fib(n - 1) + fib(n - 2)
end
puts fib(20)
`)
if err != nil {
    // err is a parse error with a line number
}
// prog is an *ast.Program; walk prog.Body ([]ast.Node).

The AST node types live in github.com/go-ruby-parser/parser/ast; the token kinds in .../token; the stateful lexer in .../lexer.

What it parses

A broad, practical subset of Ruby 4.0, all differential-tested against MRI:

  • Literals: integers (with Bignum/arbitrary precision, radix 0x/0o/ 0b/0d, underscores), floats (incl. scientific 1.5e3), strings (double- and single-quoted, interpolation, heredocs <</<<-/<<~, %q/%Q literals, the \a/\b/\v/\f/\s/\n/\t/\r/\e/\0 escapes), symbols (incl. quoted/operator), %w/%i/%W/%I arrays, arrays, hashes (incl. the {x:} value-shorthand), ranges (incl. beginless/endless), regexps (/re/imx), true/false/nil.
  • Operators: arithmetic, comparison/<=>, ==/===, bitwise/shift, &&/||/and/or/not, ternary, :: scope, safe navigation &., compound assignment (+=, -=, *=, /=, %=, <<=, ||=, &&=).
  • Control flow: if/unless/while/until (block and modifier), case/when, case/in pattern matching (array/find/hash/pin/ alternative/range patterns, guards, one-line =>/in), begin/rescue/ else/ensure/retry, break/next/return, loop.
  • Methods/blocks: required/optional/*splat/keyword/**rest/&block params, endless methods (def f = expr), setters, operator/[]/[]= method names, operator-method calls (1.+(2)), { } / do…end blocks, (a, b) destructuring group params, stabby lambdas ->(){}, numbered params (_1) and it, yield, super, multiple-value return a, b.
  • Classes/modules/metaprogramming: class/module, inheritance, @ivars, @@class variables, constants, singleton method defs (def self.foo/def obj.foo/def Const.foo), global-variable assignment ($g = …), multiple assignment / destructuring, adjacent string-literal concatenation ("a" "b").

Performance

On the both-accept corpus (the 615 harvested snippets + 110 real CRuby-4.0.5 stdlib files both engines parse), go-ruby-parser beats MRI's reference C parser: it parses 1.5× faster than RubyVM::AbstractSyntaxTree.parse on small snippets and 2.1× faster on real stdlib files, ~6× faster than Ripper.sexp, and the lexer is ~24–30× faster than Ripper.lex — all while building a full Go AST. Methodology, full parity tables, and the allocation hotspots / action items are in BENCHMARKS.md; reproduce with benchmarks/run.sh (an isolated module, outside the coverage gate).

Known limitations

The following are not yet parsed (they remain on go-embedded-ruby's roadmap; contributions welcome):

  • paren-less command calls with keyword/splat/block args (foo a: 1)
  • default block parameters ({ |a = 1| }) — splat block params ({ |*a| }) are supported
  • the positional Class(a) find-pattern (Class[a] is supported)

License

BSD-3-Clause © the go-ruby-parser/parser authors.

WebAssembly

Being pure Go (CGO=0), this library also compiles to WebAssembly — both GOOS=js GOARCH=wasm (browser / Node.js) and GOOS=wasip1 GOARCH=wasm (WASI). CI builds both targets on every push, alongside the six 64-bit native/qemu arches.

GOOS=js     GOARCH=wasm go build ./...   # browser / Node
GOOS=wasip1 GOARCH=wasm go build ./...   # WASI (wasmtime, wasmer, wasmedge, …)

Documentation

Overview

Package parser builds an AST from tokens: recursive descent for statements, Pratt (precedence-climbing) for expressions, and a scope stack to resolve the classic local-variable-vs-method-call ambiguity (plan-rbgo.md §10).

The scope stack is what lets `foo` mean a variable read when `foo` was assigned earlier in the same def, and a (possibly command-style) method call otherwise — exactly MRI's rule.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Parse

func Parse(src string) (prog *ast.Program, err error)

Parse lexes and parses src into a Program. It never panics: a malformed input yields a parse error, and any unexpected internal panic is also surfaced as a parse error rather than propagating to the caller.

Types

type Parser

type Parser struct {
	// contains filtered or unexported fields
}

Parser holds parsing state.

Directories

Path Synopsis
Package ast defines the Phase 0 abstract syntax tree.
Package ast defines the Phase 0 abstract syntax tree.
Package lexer turns source bytes into tokens.
Package lexer turns source bytes into tokens.
Package token defines the lexical tokens for the Phase 0 subset.
Package token defines the lexical tokens for the Phase 0 subset.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL