Lines Matching full:we
1 //! In this example we build an [S-expression](https://en.wikipedia.org/wiki/S-expression)
18 /// We start by defining the types that define the shape of data that we want.
19 /// In this case, we want something tree-like
21 /// Starting from the most basic, we define some built-in functions that our lisp has
32 /// We now wrap this type and a few other primitives into our Atom type.
43 /// The remaining half is Lists. We implement these as recursive Expressions.
44 /// For a list of numbers, we have `'(1 2 3)`, which we'll parse to:
50 /// structure that we can deal with programmatically. Thus any valid expression
67 /// we start by creating a parser for the built-in operator functions.
69 // one_of matches one of the characters we give it in parse_builtin_op()
72 // because we are matching single character tokens, we can do the matching logic in parse_builtin_op()
89 // parsers we give it in parse_builtin()
92 // map lets us process the parsed output, in this case we know what we parsed, in parse_builtin()
93 // so we ignore the input and return the BuiltIn directly in parse_builtin()
98 /// Our boolean values are also constant, so we can do it the same way
107 /// We introduce some error handling combinators: `context` for human readable errors
110 /// Put plainly: `preceded(tag(":"), cut(alpha1))` means that once we see the `:`
111 /// character, we have to see one or more alphabetic chararcters or the input is invalid.
119 /// Next up is number parsing. We're keeping it simple here by accepting any number (> 1)
132 /// Now we take all these simple parsers and connect them.
133 /// We can now parse half of our language!
143 /// We then add the Expr layer on top
148 /// Before continuing, we need a helper function to parse lists.
150 /// By putting whitespace and newline parsing here, we can avoid having to worry about it
166 /// We can now use our new combinator to define the rest of the `Expr`s.
168 /// Starting with function application, we can see how the parser mirrors our data
169 /// definitions: our definition is `Application(Box<Expr>, Vec<Expr>)`, so we know
170 /// that we need to parse an expression and then parse 0 or more expressions, all
173 /// `tuple` is used to sequence parsers together, so we can translate this directly
179 // finally, we wrap it in an s-expression in parse_application()
183 /// Because `Expr::If` and `Expr::IfElse` are so similar (we easily could have
184 /// defined `Expr::If` to have an `Option` for the else block), we parse both
187 /// In fact, we define our parser as if `Expr::If` was defined with an Option in it,
188 /// we have the `opt` combinator which fits very nicely here.
194 // here to avoid ambiguity with other names starting with `if`, if we added in parse_if()
195 // variables to our language, we say that if must be terminated by at least in parse_if()
219 /// the definition of quote to not always be around an S-expression, we'd get them
222 // this should look very straight-forward after all we've done: in parse_quote()
223 // we find the `'` (quote) character, use cut to say that we're unambiguously in parse_quote()
231 /// We tie them all together again, making a top-level expression parser!
241 /// We can now parse our entire lisp language.
243 /// But in order to make it a little more interesting, we can hack together
248 /// To start we define a couple of helper functions
272 // we then recursively `eval_expression` in the context of our special forms in eval_expression()
359 /// And we add one more top-level function to tie everything together, letting