File: ident.ha

package info (click to toggle)
hare-update 0.26.0.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,044 kB
  • sloc: makefile: 37; sh: 14
file content (70 lines) | stat: -rw-r--r-- 1,948 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// SPDX-License-Identifier: MPL-2.0
// (c) Hare authors <https://harelang.org>

use bufio;
use common;
use common::{ltok, nonterminal};
use memio;
use strings;
use vNEXT::ast;
use vNEXT::lex;

// Parses a single identifier, possibly with a trailing ::, i.e. 'foo::bar::'.
// Returns the identifier and whether there's a trailing ::.
export fn ident_trailing(lexer: *lex::lexer) ((ast::ident, bool) | error) = {
	let ident: []str = [];
	let trailing = false;
	const tok = want(lexer, ltok::NAME)?;
	append(ident, tok.1 as str)!;
	const loc = tok.2;
	let z = len(ident[0]);
	for (true) {
		match (try(lexer, ltok::DOUBLE_COLON)?) {
		case void => break;
		case => void; // Grab the next ident
		};
		z += 1;
		let name = match (try(lexer, ltok::NAME, ltok::NOMEM)?) {
		case let t: common::token =>
			// 0.24.2 should parse "errors::nomem" as an ident
			yield switch (t.0) {
			case ltok::NAME =>
				yield t.1 as str;
			case ltok::NOMEM =>
				yield strings::dup("nomem")!;
			case => abort();
			};
		case void =>
			trailing = true;
			break;
		};
		append(ident, name)!;
		z += len(name);
	};
	if (z > ast::IDENT_MAX) {
		ast::ident_free(ident: ast::ident);
		return syntaxerr(loc, "Identifier exceeds maximum length");
	};
	return (ident: ast::ident, trailing);
};

// Parses a single identifier, i.e. 'foo::bar::baz'.
export fn ident(lexer: *lex::lexer) (ast::ident | error) = {
	on(lexer, nonterminal::IDENTIFIER)?;

	let ident = ident_trailing(lexer)?;
	synassert(lex::mkloc(lexer), !ident.1, "Unexpected trailing :: in ident")?;
	return ident.0;
};

// A convenience function which parses an identifier from a string, so the
// caller needn't provide a lexer instance.
export fn identstr(in: str) (ast::ident | error) = {
	let in = memio::fixed(strings::toutf8(in));
	let sc = bufio::newscanner(&in);
	defer bufio::finish(&sc);
	let lexer = lex::init(&sc, "<string>");
	let ret = ident(&lexer);
	want(&lexer, ltok::EOF)?;
	return ret;
};