@@ 8,12 8,23 @@ export type error = !(io::error | utf8::invalid | unexpected);
export type symbol = str;
export type lparen = void;
export type rparen = void;
-export type token = (lparen | rparen | symbol | str | io::EOF);
+export type equals = void;
+export type token = (lparen | rparen | equals | symbol | str | io::EOF);
-fn lexstr(in: io::handle) (token | error) = {
+export type lexer = struct {
+ in: io::handle,
+ unlex: []token,
+};
+
+export fn init(in: io::handle) lexer = lexer {
+ in = in,
+ unlex = [],
+};
+
+fn lexstr(l: *lexer) (token | error) = {
let escaped = false;
let buf = strio::dynamic();
- for (true) match (bufio::scanrune(in)?) {
+ for (true) match (bufio::scanrune(l.in)?) {
case io::EOF => return io::EOF: unexpected;
case let r: rune =>
if (r == '"' && !escaped) break;
@@ 27,15 38,15 @@ fn lexstr(in: io::handle) (token | error) = {
return strio::string(&buf);
};
-fn lexsym(in: io::handle, start: rune) (token | error) = {
+fn lexsym(l: *lexer, start: rune) (token | error) = {
let buf = strio::dynamic();
strio::appendrune(&buf, start)?;
- for (true) match (bufio::scanrune(in)?) {
+ for (true) match (bufio::scanrune(l.in)?) {
case io::EOF => break;
case let r: rune =>
switch (r) {
- case ' ', '\t', '\n', '(', ')', '"' =>
- bufio::unreadrune(in, r);
+ case ' ', '\t', '\n', '(', ')', '"', '=' =>
+ bufio::unreadrune(l.in, r);
break;
case =>
strio::appendrune(&buf, r)?;
@@ 44,19 55,29 @@ fn lexsym(in: io::handle, start: rune) (token | error) = {
return strio::string(&buf): symbol;
};
-export fn lex(in: io::handle) (token | error) = match (bufio::scanrune(in)?) {
-case io::EOF => return io::EOF: token;
-case let r: rune =>
- switch (r) {
- case ' ', '\t', '\n' =>
- return lex(in);
- case '(' =>
- return lparen;
- case ')' =>
- return rparen;
- case '"' =>
- return lexstr(in);
- case =>
- return lexsym(in, r);
+export fn unlex(l: *lexer, t: token) void = append(l.unlex, t);
+
+export fn lex(l: *lexer) (token | error) = {
+ if (len(l.unlex) > 0) {
+ defer delete(l.unlex[len(l.unlex) - 1]);
+ return l.unlex[len(l.unlex) - 1];
+ };
+ match (bufio::scanrune(l.in)?) {
+ case io::EOF => return io::EOF: token;
+ case let r: rune =>
+ switch (r) {
+ case ' ', '\t', '\n' =>
+ return lex(l);
+ case '(' =>
+ return lparen;
+ case ')' =>
+ return rparen;
+ case '=' =>
+ return equals;
+ case '"' =>
+ return lexstr(l);
+ case =>
+ return lexsym(l, r);
+ };
};
};
@@ 5,19 5,22 @@ use expr;
export type unexpected = !lex::token;
export type error = !(lex::error | unexpected);
-fn parselist(in: io::handle) (expr::expr | error) = {
- let t = lex::lex(in)?;
+fn parselist(l: *lex::lexer) (expr::expr | error) = {
+ let t = lex::lex(l)?;
if (t is lex::rparen) return void;
- let first = _parse(in, t)?;
- let rest = parselist(in)?;
+ let first = parset(l, t)?;
+ let rest = parselist(l)?;
return alloc((first, rest));
};
-fn _parse(in: io::handle, t: lex::token) (expr::expr | error) = match (t) {
+fn parset(l: *lex::lexer, t: lex::token) (expr::expr | error) = match (t) {
case lex::lparen =>
- return parselist(in);
+ return parselist(l);
case let s: lex::symbol =>
- if (s == "param") return ("foo","bar"): expr::param;
+ let t = lex::lex(l)?;
+ //TODO abort -> error handling
+ if (t is lex::equals) return (s, _parse(l)? as str): expr::param;
+ lex::unlex(l, t);
return s: expr::symbol;
case let s: str =>
return s: expr::expr;
@@ 25,4 28,6 @@ case =>
return t: unexpected;
};
-export fn parse(in: io::handle) (expr::expr | error) = _parse(in, lex::lex(in)?);
+fn _parse(l: *lex::lexer) (expr::expr | error) = parset(l, lex::lex(l)?);
+
+export fn parse(in: io::handle) (expr::expr | error) = _parse(&lex::init(in));