commit d003ed892c49810aacc0f81d418692412bcc835b
parent 3c90d8bc46e9a957bc28559a3de3698fdfecbcb6
Author: Drew DeVault <sir@cmpwn.com>
Date: Fri, 26 Feb 2021 15:42:15 -0500
hare::module: scan imports
Diffstat:
6 files changed, 77 insertions(+), 25 deletions(-)
diff --git a/hare/ast/types.ha b/hare/ast/types.ha
@@ -15,6 +15,19 @@ export fn ident_free(ident: ident) void = {
free(ident);
};
+// Returns true if two idents are identical.
+export fn ident_eq(a: ident, b: ident) bool = {
+ if (len(a) != len(b)) {
+ return false;
+ };
+ for (let i = 0z; i < len(a); i += 1) {
+ if (a[i] != b[i]) {
+ return false;
+ };
+ };
+ return true;
+};
+
// A sub-unit, typically representing a single source file.
export type subunit = struct {
imports: []import,
diff --git a/hare/lex/+test.ha b/hare/lex/+test.ha
@@ -6,7 +6,7 @@ use strings;
@test fn unget() void = {
let buf = bufio::fixed(strings::to_utf8("z"), mode::READ);
- let lexer = lexer_init(buf, "<test>");
+ let lexer = init(buf, "<test>");
unget(&lexer, 'x');
unget(&lexer, 'y');
assert(next(&lexer) as rune == 'y');
@@ -18,7 +18,7 @@ use strings;
};
@test fn unlex() void = {
- let lexer = lexer_init(io::empty, "<test>");
+ let lexer = init(io::empty, "<test>");
unlex(&lexer, (btoken::IF, location {
path = "<test>",
line = 1234,
@@ -58,7 +58,7 @@ fn liteq(expected: literal, actual: literal) bool = {
fn lextest(in: str, expected: [](uint, uint, token)) void = {
let buf = bufio::fixed(strings::to_utf8(in), mode::READ);
- let lexer = lexer_init(buf, "<test>");
+ let lexer = init(buf, "<test>");
for (let i = 0z; i < len(expected); i += 1) {
let eline = expected[i].0, ecol = expected[i].1,
etok = expected[i].2;
@@ -191,7 +191,7 @@ fn lextest(in: str, expected: [](uint, uint, token)) void = {
@test fn keywords() void = {
let keywords = bmap[..btoken::LAST_KEYWORD+1];
for (let i = 0z; i < len(keywords); i += 1) {
- let lexer = lexer_init(bufio::fixed(
+ let lexer = init(bufio::fixed(
strings::to_utf8(keywords[i]), mode::READ),
"<test>");
let tl = match (lex(&lexer)) {
diff --git a/hare/lex/lex.ha b/hare/lex/lex.ha
@@ -33,7 +33,7 @@ export fn errstr(err: error) const str = {
};
// Initializes a new lexer for the given input stream. The path is borrowed.
-export fn lexer_init(in: *io::stream, path: str) lexer = lexer {
+export fn init(in: *io::stream, path: str) lexer = lexer {
in = in,
path = path,
loc = (1, 1),
diff --git a/hare/module/scan.ha b/hare/module/scan.ha
@@ -1,39 +1,35 @@
use crypto::sha256;
use fs;
use hare::ast;
+use hare::lex;
+use hare::parse;
use hash;
use io;
use path;
use slice;
use strings;
-fn hash_file(ctx: *context, path: path::path) ([]u8 | error) = {
- let sha = sha256::sha256();
- //defer! hash::close(sha);
- let f = fs::open(ctx.fs, path, io::mode::READ)?;
- io::copy(hash::writer(sha), f)?;
- return hash::finish(sha);
-};
-
// Scans the files in a directory for eligible build inputs and returns a
-// [version] which includes all applicable files.
+// [version] which includes all applicable files and their dependencies.
export fn scan(ctx: *context, path: path::path) (version | error) = {
let sha = sha256::sha256();
//defer! hash::close(sha);
let inputs: []input = [];
+ let deps: []ast::ident = [];
let iter = match (fs::iter(ctx.fs, path)) {
fs::wrongtype => {
let st = fs::stat(ctx.fs, path)?;
let in = input {
path = path,
stat = st,
- hash = hash_file(ctx, path)?,
+ hash = scan_file(ctx, path, &deps)?,
...
};
append(inputs, in);
hash::write(sha, in.hash);
return version {
hash = hash::finish(sha),
+ depends = deps,
inputs = inputs,
};
},
@@ -51,7 +47,7 @@ export fn scan(ctx: *context, path: path::path) (version | error) = {
let in = input {
path = p,
stat = st,
- hash = hash_file(ctx, p)?,
+ hash = scan_file(ctx, p, &deps)?,
...
};
append(inputs, in);
@@ -62,6 +58,7 @@ export fn scan(ctx: *context, path: path::path) (version | error) = {
};
return version {
hash = hash::finish(sha),
+ depends = deps,
inputs = inputs,
};
};
@@ -86,3 +83,41 @@ fn eligible(ctx: *context, name: path::path) bool = {
};
return false;
};
+
+fn scan_file(
+ ctx: *context,
+ path: path::path,
+ deps: *[]ast::ident,
+) ([]u8 | error) = {
+ let f = fs::open(ctx.fs, path, io::mode::READ)?;
+ let sha = sha256::sha256();
+ //defer! hash::close(sha);
+ let tee = io::tee(f, hash::writer(sha));
+ defer io::close(tee);
+
+ let lexer = lex::init(tee, path as str);
+ let imports = parse::imports(&lexer)?;
+ for (let i = 0z; i < len(imports); i += 1) {
+ let ident = match (imports[i]) {
+ m: ast::import_module => m: ast::ident,
+ a: ast::import_alias => a.ident,
+ o: ast::import_objects => o.ident,
+ };
+ if (!have_ident(deps, ident)) {
+ append(*deps, ident);
+ };
+ };
+
+ io::copy(io::empty, tee)?; // Finish spooling out the file for the SHA
+ return hash::finish(sha);
+};
+
+fn have_ident(sl: *[]ast::ident, id: ast::ident) bool = {
+ // XXX: We shouldn't have to deref sl here
+ for (let i = 0z; i < len(*sl); i += 1) {
+ if (ast::ident_eq(sl[i], id)) {
+ return true;
+ };
+ };
+ return false;
+};
diff --git a/hare/module/types.ha b/hare/module/types.ha
@@ -1,4 +1,6 @@
use fs;
+use hare::ast;
+use hare::parse;
use io;
use path;
@@ -24,6 +26,7 @@ export type manifest = struct {
// A module version: a set of possible input files for that module.
export type version = struct {
hash: []u8,
+ depends: []ast::ident,
inputs: []input,
};
@@ -38,10 +41,11 @@ export type input = struct {
export type module_not_found = void!;
// All possible error types.
-export type error = (fs::error | io::error | module_not_found)!;
+export type error = (fs::error | io::error | parse::error | module_not_found)!;
export fn errstr(err: error) const str = match (err) {
err: fs::error => fs::errstr(err),
err: io::error => io::errstr(err),
+ err: parse::error => parse::errstr(err),
module_not_found => "Module not found",
};
diff --git a/hare/parse/+test.ha b/hare/parse/+test.ha
@@ -9,7 +9,7 @@ use strings;
{
const in = "foo";
let buf = bufio::fixed(strings::to_utf8(in), mode::READ);
- let lexer = lex::lexer_init(buf, "<test>");
+ let lexer = lex::init(buf, "<test>");
let ident = ident(&lexer) as ast::ident;
defer ast::ident_free(ident);
assert(len(ident) == 1);
@@ -20,7 +20,7 @@ use strings;
{
const in = "foo::bar";
let buf = bufio::fixed(strings::to_utf8(in), mode::READ);
- let lexer = lex::lexer_init(buf, "<test>");
+ let lexer = lex::init(buf, "<test>");
let ident = ident(&lexer) as ast::ident;
defer ast::ident_free(ident);
assert(len(ident) == 2);
@@ -31,7 +31,7 @@ use strings;
{
const in = "foo::bar::baz";
let buf = bufio::fixed(strings::to_utf8(in), mode::READ);
- let lexer = lex::lexer_init(buf, "<test>");
+ let lexer = lex::init(buf, "<test>");
let ident = ident(&lexer) as ast::ident;
defer ast::ident_free(ident);
assert(len(ident) == 3);
@@ -43,7 +43,7 @@ use strings;
{
const in = "foo::bar;";
let buf = bufio::fixed(strings::to_utf8(in), mode::READ);
- let lexer = lex::lexer_init(buf, "<test>");
+ let lexer = lex::init(buf, "<test>");
let ident = ident(&lexer) as ast::ident;
defer ast::ident_free(ident);
assert(len(ident) == 2);
@@ -57,7 +57,7 @@ use strings;
{
const in = "use foo;";
let buf = bufio::fixed(strings::to_utf8(in), mode::READ);
- let lexer = lex::lexer_init(buf, "<test>");
+ let lexer = lex::init(buf, "<test>");
let mods = imports(&lexer) as []ast::import;
defer for (let i = 0z; i < len(mods); i += 1) {
ast::import_free(mods[i]);
@@ -78,7 +78,7 @@ use strings;
"use baz::bat;\n\n"
"export fn main() void = void;";
let buf = bufio::fixed(strings::to_utf8(in), mode::READ);
- let lexer = lex::lexer_init(buf, "<test>");
+ let lexer = lex::init(buf, "<test>");
let mods = imports(&lexer) as []ast::import;
defer for (let i = 0z; i < len(mods); i += 1) {
ast::import_free(mods[i]);
@@ -107,7 +107,7 @@ use strings;
"use qux = quux::corge;\n"
"export fn main() void = void;";
let buf = bufio::fixed(strings::to_utf8(in), mode::READ);
- let lexer = lex::lexer_init(buf, "<test>");
+ let lexer = lex::init(buf, "<test>");
let mods = imports(&lexer) as []ast::import;
defer for (let i = 0z; i < len(mods); i += 1) {
ast::import_free(mods[i]);
@@ -138,7 +138,7 @@ use strings;
"use quux::corge::{grault, garply,};\n"
"export fn main() void = void;";
let buf = bufio::fixed(strings::to_utf8(in), mode::READ);
- let lexer = lex::lexer_init(buf, "<test>");
+ let lexer = lex::init(buf, "<test>");
let mods = imports(&lexer) as []ast::import;
defer for (let i = 0z; i < len(mods); i += 1) {
ast::import_free(mods[i]);