~tomleb/hare-langtools

f8fb6b063837795663cef2fa6f7536fe9b06ca21 — Tom Lebreux 6 months ago a090b45 master
Resolve ident for const/global, add more tests
3 files changed, 246 insertions(+), 30 deletions(-)

M cmd/resolvident/decl.ha
M cmd/resolvident/main.ha
M cmd/resolvident/test.ha
M cmd/resolvident/decl.ha => cmd/resolvident/decl.ha +113 -19
@@ 3,58 3,152 @@ use fmt;
use hare::ast;
use hare::lex;

fn find_closest_decl(decl: ast::decl, loc: lex::location) (ast::expr | ast::ident | void) = {
fn find_closest_decl(decl: ast::decl, loc: lex::location) (ast::expr | ast::_type | void) = {
	match (decl.decl) {
	case let types: []ast::decl_type =>
		for (let i = 0z; i < len(types); i += 1) {
			fmt::println("type", identstr(types[i].ident))!;
			match (find_closest_decl_type(types[i]._type, loc)) {
			case let expr: ast::expr =>
				return expr;
			case let ident: ast::ident =>
				return ident;
			case let result: (ast::expr | ast::_type) =>
				return result;
			case void => void;
			};
		};
	case let func: ast::decl_func =>
		return find_closest_decl_func_expr(func, loc);
	case let globals: []ast::decl_global =>
		for (let i = 0z; i < len(globals); i += 1) {
			match (find_closest_decl_global(globals[i], loc)) {
			case let result: (ast::expr | ast::_type) =>
				return result;
			case void => void;
			};
		};
	case let consts: []ast::decl_const =>
		for (let i = 0z; i < len(consts); i += 1) {
			match (find_closest_decl_const(consts[i], loc)) {
			case let result: (ast::expr | ast::_type) =>
				return result;
			case void => void;
			};
		};
	case let f: ast::decl_func =>
		fmt::println("fn", identstr(f.ident))!;
		return find_closest_decl_func_expr(f, loc);
	};
};

fn find_closest_decl_types(types: []*ast::_type, loc: lex::location) (ast::expr | ast::ident | void) = {
	for (let i = 0z; i < len(types); i += 1) {
		match (find_closest_decl_type(*types[i], loc)) {
fn find_closest_decl_const(_const: ast::decl_const, loc: lex::location) (ast::expr | ast::_type | void) = {
	match (find_closest_expr(*_const.init, loc)) {
	case let expr: ast::expr =>
		return expr;
	case void => void;
	};

	return find_closest_decl_type(_const._type, loc);
};

fn find_closest_decl_global(global: ast::decl_global, loc: lex::location) (ast::expr | ast::_type | void) = {
	match (global.init) {
	case null => void;
	case let expr: *ast::expr =>
		match (find_closest_expr(*expr, loc)) {
		case let expr: ast::expr =>
			return expr;
		case let ident: ast::ident =>
			return ident;
		case void => void;
		};
	};

	return find_closest_decl_type(global._type, loc);
};

fn find_closest_decl_types(types: []*ast::_type, loc: lex::location) (ast::expr | ast::_type | void) = {
	for (let i = 0z; i < len(types); i += 1) {
		match (find_closest_decl_type(*types[i], loc)) {
		case let result: (ast::expr | ast::_type) =>
			return result;
		case void => void;
		};
	};
};

fn find_closest_decl_type(_type: ast::_type, loc: lex::location) (ast::expr | ast::ident | void) = {
fn find_closest_decl_type(_type: ast::_type, loc: lex::location) (ast::expr | ast::_type | void) = {
	if (!loc_between(loc, _type.start, _type.end)) {
		return;
	};

	match (_type.repr) {
	case let alias: ast::alias_type =>
		return alias.ident;
		return _type;
	case let func: ast::func_type =>
		return find_closest_decl_type_func(func, loc);
	case let list: ast::list_type =>
		return find_closest_decl_type_list(list, loc);
	case let ptr: ast::pointer_type =>
		return find_closest_decl_type(*ptr.referent, loc);
	case let tagged: ast::tagged_type =>
		return find_closest_decl_types(tagged: []*ast::_type, loc);
		return find_closest_decl_types(tagged, loc);
	case let tuple: ast::tuple_type =>
		return find_closest_decl_types(tuple: []*ast::_type, loc);
		return find_closest_decl_types(tuple, loc);
	case let _struct: ast::struct_type =>
		return find_closest_decl_type_struct_members(_struct, loc);
	case let _union: ast::union_type =>
		return find_closest_decl_type_struct_members(_union, loc);
	case => void;
	};
};

fn find_closest_decl_type_func(func: ast::func_type, loc: lex::location) (ast::expr | ast::_type | void) = {
	match (find_closest_decl_type(*func.result, loc)) {
	case let result: (ast::expr | ast::_type) =>
		return result;
	case => void;
	};

	for (let i = 0z; i < len(func.params); i += 1) {
		match (find_closest_decl_type(*func.params[i]._type, loc)) {
		case let result: (ast::expr | ast::_type) =>
			return result;
		case => void;
		};
	};
};

fn find_closest_decl_type_struct_member(member: ast::struct_member, loc: lex::location) (ast::expr | ast::_type | void) = {
	match (member._offset) {
	case null => void;
	case let _offset: *ast::expr =>
		match (find_closest_expr(*_offset, loc)) {
		case let expr: ast::expr =>
			return expr;
		case => void;
		};
	};

	match (member.member) {
	// FIXME: struct_alias does not have a location
	case let alias: ast::struct_alias =>
		return;
	// Example:
	// type foo = {
	// 	struct {
	// 		foo: bar,
	// 	},
	// };   
	case let embedded: ast::struct_embedded =>
		return find_closest_decl_type(*embedded, loc);
	case let field: ast::struct_field =>
		return find_closest_decl_type(*field._type, loc);
	};
};

fn find_closest_decl_type_struct_members(members: []ast::struct_member, loc: lex::location) (ast::expr | ast::_type | void) = {
	for (let i = 0z; i < len(members); i += 1) {
		match (find_closest_decl_type_struct_member(members[i], loc)) {
		case let result: (ast::expr | ast::_type) =>
			return result;
		case => void;
		};
	};
};

fn find_closest_decl_type_list(list: ast::list_type, loc: lex::location) (ast::expr | ast::ident | void) = {
fn find_closest_decl_type_list(list: ast::list_type, loc: lex::location) (ast::expr | ast::_type | void) = {
	match (list.length) {
	case let expr: *ast::expr =>
		match (find_closest_expr(*expr, loc)) {

M cmd/resolvident/main.ha => cmd/resolvident/main.ha +9 -11
@@ 20,17 20,17 @@ fn do(in: io::handle, path: str, loc: lex::location) (str | void | parse::error)
		let stream = strio::dynamic();
		defer io::close(&stream)!;

		fmt::println("Found closest expression between", locstr(expr.start), "and", locstr(expr.end))!;

		unparse::expr(&stream, 0, expr)!;
		fmt::println(strio::string(&stream))!;
		yield match (expr_to_ident(expr)) {
		case let ident: ast::ident =>
			yield ident;
		case void => return;
		};
	case let ident: ast::ident =>
		yield ident;
	case let _type: ast::_type =>
		yield match (_type.repr) {
		case let alias: ast::alias_type =>
			yield alias.ident;
		case => abort();
		};
	case void =>
		fmt::println("Nothing found closest to ", locstr(loc))!;
		return;


@@ 105,7 105,7 @@ fn resolve(import: []str, expr: []str) str = {
	return strings::dup(strio::string(&s));
};

fn find_closest(subunit: ast::subunit, loc: lex::location) (ast::expr | ast::ident | void) = {
fn find_closest(subunit: ast::subunit, loc: lex::location) (ast::expr | ast::_type | void) = {
	// TODO: imports don't have location
	for (let i = 0z; i < len(subunit.imports); i += 1) {
		continue;


@@ 114,10 114,8 @@ fn find_closest(subunit: ast::subunit, loc: lex::location) (ast::expr | ast::ide
	for (let i = 0z; i < len(subunit.decls); i += 1) {
		const decl = subunit.decls[i];
		match (find_closest_decl(decl, loc)) {
		case let expr: ast::expr =>
			return expr;
		case let ident: ast::ident =>
			return ident;
		case let result: (ast::expr | ast::_type) =>
			return result;
		case => void;
		};
	};

M cmd/resolvident/test.ha => cmd/resolvident/test.ha +124 -0
@@ 6,6 6,130 @@ use hare::parse;
use io;
use strings;

@test fn test_decl_type_const() void = {
	const src =
"use toto::foo;
def bar: foo::bar = foo::BUFSIZE;";
	const loc = lex::location {
		line = 2,
		col = 12,
		...
	};
	const expected = "toto::foo::bar";
	testfound(src, loc, expected);

	const loc = lex::location {
		line = 2,
		col = 23,
		...
	};
	const expected = "toto::foo::BUFSIZE";
	testfound(src, loc, expected);
};

@test fn test_decl_type_global() void = {
	const src =
"use toto::foo;
const bar: foo::bar;
let baz: foo::baz = foo::BUFSIZE;";
	const loc = lex::location {
		line = 2,
		col = 12,
		...
	};
	const expected = "toto::foo::bar";
	testfound(src, loc, expected);

	const loc = lex::location {
		line = 3,
		col = 11,
		...
	};
	const expected = "toto::foo::baz";
	testfound(src, loc, expected);

	const loc = lex::location {
		line = 3,
		col = 21,
		...
	};
	const expected = "toto::foo::BUFSIZE";
	testfound(src, loc, expected);
};

@test fn test_decl_type_func() void = {
	const src =
"use toto::foo;
type toto = fn(foo: int, bar: foo::bar) foo::baz;";
	const loc = lex::location {
		line = 2,
		col = 31,
		...
	};
	const expected = "toto::foo::bar";
	testfound(src, loc, expected);

	const loc = lex::location {
		line = 2,
		col = 41,
		...
	};
	const expected = "toto::foo::baz";
	testfound(src, loc, expected);
};

@test fn test_decl_type_struct() void = {
	const src =
"use toto::foo;
type toto = struct {
	bar: foo::bar,
	struct {
		foobar: foo::baz,
	},
};";
	const loc = lex::location {
		line = 3,
		col = 15,
		...
	};
	const expected = "toto::foo::bar";
	testfound(src, loc, expected);

	const loc = lex::location {
		line = 5,
		col = 25,
		...
	};
	const expected = "toto::foo::baz";
	testfound(src, loc, expected);
};

@test fn test_decl_type_struct() void = {
	const src =
"use toto::foo;
type toto = struct {
	bar: foo::bar,
	struct {
		foobar: foo::baz,
	},
};";
	const loc = lex::location {
		line = 3,
		col = 15,
		...
	};
	const expected = "toto::foo::bar";
	testfound(src, loc, expected);

	const loc = lex::location {
		line = 5,
		col = 25,
		...
	};
	const expected = "toto::foo::baz";
	testfound(src, loc, expected);
};

@test fn test_decl_type_tuple() void = {
	const src =
"use foo;