~evan/weblisp

1575e2031ee1aa7f735b8e741a594d6f6b0edccd — Evan Johnston a year ago 058cb92
add syntax for params
2 files changed, 55 insertions(+), 29 deletions(-)

M lex/lex.ha
M parse/parse.ha
M lex/lex.ha => lex/lex.ha +42 -21
@@ 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);
		};
	};
};

M parse/parse.ha => parse/parse.ha +13 -8
@@ 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));