Documentation
¶
Overview ¶
Package parser implements R7RS Scheme syntax parsing.
The parser converts a token stream into syntax values with source location:
Features ¶
- All Scheme datums: literals, symbols, lists, vectors, bytevectors
- Full numeric tower: integers, floats, rationals, complex, big numbers
- Quote forms: ', `, ,, ,@ and syntax variants #', #`, #,, #,@
- Datum labels: #n= and #n# for shared/circular structures (R7RS 2.4)
- Case folding: #!fold-case and #!no-fold-case directives
- Symbol interning at parse time
Usage ¶
p := parser.NewParserWithFile(env, true, reader, "example.scm")
for {
stx, err := p.ReadSyntax(ctx)
if err == io.EOF {
break
}
// process stx
}
Error Handling ¶
Parse errors are wrapped in ParserError with source location from the offending token. The parser accumulates no state across expressions.
Index ¶
- Constants
- Variables
- func ParseComplexStringNumber(s string) (values.Number, error)
- func ParseImaginaryStringNumber(s string) (values.Number, error)
- func ParseRealFloatString(s string) (values.Number, error)
- func ParseSpecialFloat(s string) (*values.Float, bool)
- type Parser
- type ParserError
- func NewParserError(tok tokenizer.Token, mess string) *ParserError
- func NewParserErrorWithWrap(err error, tok tokenizer.Token, mess string) *ParserError
- func NewParserErrorWithWrapf(err error, tok tokenizer.Token, mess string, vs ...any) *ParserError
- func NewParserErrorf(tok tokenizer.Token, mess string, vs ...any) *ParserError
Constants ¶
const ( ConstQuote = "quote" ConstQuasiquote = "quasiquote" ConstUnquote = "unquote" ConstUnquoteSplicing = "unquote-splicing" ConstSyntax = "syntax" ConstQuasisyntax = "quasisyntax" ConstUnsyntax = "unsyntax" ConstUnsyntaxSplicing = "unsyntax-splicing" )
Quote form identifiers.
const DefaultMaxParseDepth int = 10000
DefaultMaxParseDepth bounds structural nesting depth during parsing. Without a bound, adversarial input such as deeply nested parentheses triggers a fatal, unrecoverable Go stack overflow that kills the host process. 0 means unlimited. Mirrors the VM's DefaultMaxCallDepth.
Variables ¶
var ( // ErrUnknownTokenType is returned when the parser encounters an unrecognized token. ErrUnknownTokenType = werr.NewStaticError("unknown token type") ErrAlreadyClosed = werr.NewStaticError("parser already closed") )
Functions ¶
func ParseComplexStringNumber ¶
ParseComplexStringNumber parses a rectangular complex number string ending in 'i'. Handles "3+4i", "1.5-2.5i", "1+inf.0i", "0+3/4i", etc.
On reject it returns a non-nil error carrying a werr sentinel (ErrInvalidFormat for a shape that is not this grammar; the part parser's own sentinel for a malformed real/imaginary part). See ParseImaginaryStringNumber for how the two callers treat the error differently.
func ParseImaginaryStringNumber ¶
ParseImaginaryStringNumber parses a pure imaginary string (ending in 'i') and returns the resulting complex number. Handles "+3i", "-2.5i", "+i", "-i", "+inf.0i", "-nan.0i", etc.
On reject it returns a non-nil error carrying a werr sentinel (ErrInvalidFormat for a shape that is not this grammar; the coefficient parser's own sentinel — ErrInvalidFormat / ErrDivisionByZero — for a malformed coefficient). Callers choose how to treat it: string->number discards it and tries the next grammar (R7RS §6.2.7 returns #f), while the reader wraps it with a source location so the cause stays reachable via errors.Is / errors.Unwrap.
func ParseRealFloatString ¶
ParseRealFloatString parses a real decimal or scientific-notation string as an inexact number. In-range magnitudes yield a float64-backed Float; magnitudes beyond float64 range (strconv reports ErrRange as ±Inf) promote to a BigFloat rather than failing. This mirrors the int64 -> BigInteger promotion in parseIntegerWithBase and, crucially, keeps the reader and string->number symmetric with the writer, which renders an out-of-range bigfloat in scientific notation (e.g. (write (* 1.0 (expt 10 1000))) -> "1e+1000"). Underflow to zero (float64 rounds a tiny magnitude to 0 without ErrRange) is left as the float64 0.0 it already produces, matching float64-based Schemes. The exponent marker is normalized to 'e' first. Returns a wrapped ErrInvalidFormat sentinel on a malformed string.
Types ¶
type Parser ¶
type Parser struct {
// contains filtered or unexported fields
}
Parser represents a R7RS compliant Scheme syntax parser.
func NewParser ¶
func NewParser(env *environment.EnvironmentFrame, skipComments bool, rdr io.RuneReader) *Parser
NewParser creates a new parser for the given reader and environment.
func NewParserWithFile ¶
func NewParserWithFile(env *environment.EnvironmentFrame, skipComments bool, rdr io.RuneReader, file string) *Parser
NewParserWithFile creates a new parser with a specified source filename.
func (*Parser) ReadSyntax ¶
ReadSyntax reads and returns the next syntax value from the input. It honors ctx: a cancelled or deadline-exceeded context returns its error before reading the next form, so a long multi-form parse can be interrupted.
func (*Parser) SetFoldCase ¶
SetFoldCase enables or disables R7RS §2.1 fold-case mode at construction time, before any forms are read. This is the programmatic equivalent of a leading #!fold-case directive; it lets a caller (e.g. include-ci) read an entire file case-insensitively without the file itself carrying the directive. An in-file #!fold-case / #!no-fold-case directive still toggles the mode mid-stream.
func (*Parser) SetMaxDepth ¶
SetMaxDepth sets the maximum structural nesting depth allowed during parsing. A value of 0 (or negative, clamped to 0) disables the limit. Mirrors MachineContext.SetMaxCallDepth.
type ParserError ¶
type ParserError struct {
// contains filtered or unexported fields
}
ParserError represents an error that occurred during parsing.
The offending token (tok) carries the source position; file is the source name (empty for unnamed input such as a REPL stream). Location formats the two so the error's provenance survives to the final error chain — see REVIEW.md "Error Chain Losslessness".
func NewParserError ¶
func NewParserError(tok tokenizer.Token, mess string) *ParserError
NewParserError creates a new parser error for the given token.
func NewParserErrorWithWrap ¶
func NewParserErrorWithWrap(err error, tok tokenizer.Token, mess string) *ParserError
NewParserErrorWithWrap creates a new parser error wrapping another error.
func NewParserErrorWithWrapf ¶
NewParserErrorWithWrapf creates a new parser error wrapping another error.
func NewParserErrorf ¶
func NewParserErrorf(tok tokenizer.Token, mess string, vs ...any) *ParserError
NewParserErrorf creates a new parser error for the given token.
func (*ParserError) Error ¶
func (p *ParserError) Error() string
func (*ParserError) Is ¶
func (p *ParserError) Is(err error) bool
Is implements errors.Is for ParserError. Two parser errors match when they carry the same message (the token is positional and is not part of error identity — see EqualTo for value-level equality that includes it), so errors.Is can distinguish parser failures; a wrapped cause is still reached through Unwrap.
func (*ParserError) IsVoid ¶
func (p *ParserError) IsVoid() bool
func (*ParserError) Location ¶
func (p *ParserError) Location() string
Location returns the offending token's position as "file:line:col", or "line:col" when the input is unnamed (e.g. a REPL stream, where the parser has no file name). It returns "" when the error has no located token.
Unlike SourceContext.Location it does not require a file name, so a parse error from unnamed REPL input still reports its line and column rather than dropping the location. Line is 1-based and column 0-based, matching SourceContext.Location's formatting for parity with compiler-side locations.
func (*ParserError) SchemeString ¶
func (p *ParserError) SchemeString() string
func (*ParserError) Unwrap ¶
func (p *ParserError) Unwrap() error