% crochet

// # Parsing
//
// The grammar and AST for Crochet are defined in `grammar/pocket-lisp.lingua`,
// a PEG-based language for defining parsers. So if you haven't looked at that
// yet, you should do so first.
//
// In this file we define the *interface* for parsing Pocket Lisp programs.
// All of the methods live on the `pocket-lisp` type. For our parsing
// interface we choose to expose two functions: `try-parse: _` and
// `parse: _`. The second is a convenience where errors are handled by
// halting the program and showing the failure.
//
// Lingua, like Ohm, has a separation between parsing and semantic actions.
// Even though Lingua allows you to specify semantic actions inline in the
// grammar (in a language-agnostic way). So when we use
// grammar parse: Source rule: Starting-Rule` we get a concrete syntax tree
// back that mimics the structure defined in the grammar, and will include
// spaces and comments.
//
// In case the parsing is successful, we then use the generated semantic
// action to transform this concrete syntax tree into the abstract syntax
// tree that's defined in the grammar, using the inline semantic actions
// (which the code generator will have translated to Crochet).
//
// We expect the result of all of this, if the parser is successful, to
// be a `plisp-program`. That's pretty much just a list of Pocket Lisp
// forms.
//
// If parsing fails, however, the error reason will be a formatted string
// of what went wrong. This works great for just showing things on the
// screen, as it's presented in a human-readable way, including the offending
// portion of the source code, but it's not the best format for being able
// to programatically decide how to treat errors---this will certainly change
// in the future.

/// Attempts to parse `Source` as a Pocket Lisp program.
command pocket-lisp try-parse: (Source is text) -> result<plisp-program, text> do
  (force grammar) parse: Source rule: "Program"
    | map: { Tree in (force to-ast) transform: Tree };
end

/// Parses `Source` as a Pocket Lisp program, halts the program if parsing
/// does not succeed.
command pocket-lisp parse: (Source is text) do
  pocket-lisp try-parse: Source
    | recover: { Error in panic message: Error tag: "syntax-error" }
    | value;
end