implement: unit identity -- dotted paths, name rules, source path
Units start here, with the part that needs no import graph: what a unit is called and where it must live. The parser only ever read a single identifier after `unit` and `import`, so `unit game.main;` and `import std.io;` were syntax errors -- which is why the dotted fixtures failed at the semicolon. It now reads a dotted path and stores it canonically, dots included, since that spelling is the unit's identity everywhere else. `import a.b as c;` parses too, with the alias on the node. resolve.c is the new pass between parsing and checking, for the questions that span files. It carries SPEC 8.1 so far: each path segment is ASCII lowercase, starts with a letter, continues with letters, digits or underscore, and is at most eight characters; and the dotted path must match the source path it was read from, so game.world.map has to come from game/world/map.fe. The source side is folded to lowercase before comparing, because a case-insensitive host must not let two spellings become two units. That rule then applied to the fixtures, which were not obeying it: 57 declared a unit name unrelated to their file, left over from the milestone directories, and eight had names too long to be legal. Both are now aligned -- the rule is worth having only if the tree follows it. units: badupper, badlong and unitbad pass. 138 -> 146 of 188. The rest of units/ needs the import graph, which is the next piece: resolution, cycles, bindings and visibility.
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include "check.h"
|
#include "check.h"
|
||||||
|
#include "resolve.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -80,6 +81,15 @@ int main(int argc, char **argv)
|
|||||||
free(src);
|
free(src);
|
||||||
return d.errors?1:0;
|
return d.errors?1:0;
|
||||||
}
|
}
|
||||||
|
/* Unit identity before semantic analysis: a unit that is not named
|
||||||
|
correctly, or does not sit where its name says, cannot be resolved from
|
||||||
|
another unit either. */
|
||||||
|
fe_resolve_unit_identity(&ast,&d,file);
|
||||||
|
if(d.errors){
|
||||||
|
fe_ast_destroy(&ast);
|
||||||
|
free(src);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
fe_check_init(&check,&ast,&d,pointer_bits,no_checks);
|
fe_check_init(&check,&ast,&d,pointer_bits,no_checks);
|
||||||
if(!fe_check_program(&check)){
|
if(!fe_check_program(&check)){
|
||||||
fe_ast_destroy(&ast);
|
fe_ast_destroy(&ast);
|
||||||
|
|||||||
+37
-3
@@ -302,12 +302,46 @@ static FeNode *statement(FeParser *p)
|
|||||||
e=expr(p,0); if(is(p,FE_TOK_EQ)||is(p,FE_TOK_PLUS_EQ)||is(p,FE_TOK_MINUS_EQ)||is(p,FE_TOK_STAR_EQ)||is(p,FE_TOK_SLASH_EQ)||is(p,FE_TOK_PERCENT_EQ)||is(p,FE_TOK_AND_EQ)||is(p,FE_TOK_OR_EQ)||is(p,FE_TOK_XOR_EQ)||is(p,FE_TOK_SHL_EQ)||is(p,FE_TOK_SHR_EQ)){n=toknode(p,FE_N_ASSIGN,p->current);n->a=e;next(p);n->b=expr(p,0);}else{n=toknode(p,FE_N_EXPR_STMT,t);n->a=e;}want(p,FE_TOK_SEMI,"expected ';' after statement");return n;
|
e=expr(p,0); if(is(p,FE_TOK_EQ)||is(p,FE_TOK_PLUS_EQ)||is(p,FE_TOK_MINUS_EQ)||is(p,FE_TOK_STAR_EQ)||is(p,FE_TOK_SLASH_EQ)||is(p,FE_TOK_PERCENT_EQ)||is(p,FE_TOK_AND_EQ)||is(p,FE_TOK_OR_EQ)||is(p,FE_TOK_XOR_EQ)||is(p,FE_TOK_SHL_EQ)||is(p,FE_TOK_SHR_EQ)){n=toknode(p,FE_N_ASSIGN,p->current);n->a=e;next(p);n->b=expr(p,0);}else{n=toknode(p,FE_N_EXPR_STMT,t);n->a=e;}want(p,FE_TOK_SEMI,"expected ';' after statement");return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A unit path is dotted: `game.world.map`. It is stored canonically, dots and
|
||||||
|
all, because that spelling is the unit's identity everywhere else. */
|
||||||
|
static char *unit_path(FeParser *p)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
unsigned long len=0;
|
||||||
|
if(!is_name(p)) return 0;
|
||||||
|
for(;;) {
|
||||||
|
unsigned long n=p->current.length;
|
||||||
|
if(len && len+1<sizeof buf) buf[len++]='.';
|
||||||
|
if(len+n>=sizeof buf){error(p,"unit path is too long");return 0;}
|
||||||
|
memcpy(buf+len,p->current.begin,n);
|
||||||
|
len+=n;
|
||||||
|
next(p);
|
||||||
|
if(!eat(p,FE_TOK_DOT)) break;
|
||||||
|
if(!is_name(p)){error(p,"expected a name after '.' in unit path");return 0;}
|
||||||
|
}
|
||||||
|
return fe_arena_strdup(&p->ast->arena,buf,len);
|
||||||
|
}
|
||||||
|
|
||||||
FeNode *fe_parse_unit(FeParser *p)
|
FeNode *fe_parse_unit(FeParser *p)
|
||||||
{
|
{
|
||||||
FeToken t=p->current, name; FeNode *root;
|
FeToken t=p->current; FeNode *root; char *path;
|
||||||
if(!eat(p,FE_TOK_UNIT)){error(p,"source must start with 'unit'");return fe_node(p->ast,FE_N_ERROR_NODE,t.loc,"unit",4);}
|
if(!eat(p,FE_TOK_UNIT)){error(p,"source must start with 'unit'");return fe_node(p->ast,FE_N_ERROR_NODE,t.loc,"unit",4);}
|
||||||
root=toknode(p,FE_N_UNIT,t);if(is_name(p)){name=p->current;root->text=fe_arena_strdup(&p->ast->arena,name.begin,name.length);next(p);}else error(p,"expected unit name");want(p,FE_TOK_SEMI,"expected ';' after unit name");
|
root=toknode(p,FE_N_UNIT,t);
|
||||||
while(eat(p,FE_TOK_IMPORT)){FeToken it=p->previous;FeNode *i=toknode(p,FE_N_IMPORT,it);if(is_name(p)){next(p);i->text=fe_arena_strdup(&p->ast->arena,p->previous.begin,p->previous.length);}else error(p,"expected import name");want(p,FE_TOK_SEMI,"expected ';' after import");fe_node_add(root,i);}
|
path=unit_path(p);
|
||||||
|
if(path) root->text=path; else error(p,"expected unit name");
|
||||||
|
want(p,FE_TOK_SEMI,"expected ';' after unit name");
|
||||||
|
while(eat(p,FE_TOK_IMPORT)){
|
||||||
|
FeToken it=p->previous;FeNode *i=toknode(p,FE_N_IMPORT,it);
|
||||||
|
path=unit_path(p);
|
||||||
|
if(path) i->text=path; else error(p,"expected import name");
|
||||||
|
/* `as` renames the binding; without it the binding is the last segment. */
|
||||||
|
if(eat(p,FE_TOK_AS)) {
|
||||||
|
if(is_name(p)){i->aux_text=fe_arena_strdup(&p->ast->arena,p->current.begin,p->current.length);next(p);}
|
||||||
|
else error(p,"expected an alias name after 'as'");
|
||||||
|
}
|
||||||
|
want(p,FE_TOK_SEMI,"expected ';' after import");
|
||||||
|
fe_node_add(root,i);
|
||||||
|
}
|
||||||
while(!is(p,FE_TOK_EOF)){FeNode *d=decl(p);if(d)fe_node_add(root,d);}
|
while(!is(p,FE_TOK_EOF)){FeNode *d=decl(p);if(d)fe_node_add(root,d);}
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
#include "resolve.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static int segment_ok(const char *s, unsigned long n, const char **why)
|
||||||
|
{
|
||||||
|
unsigned long i;
|
||||||
|
if (!n) { *why = "unit path segment is empty"; return 0; }
|
||||||
|
if (n > FE_UNIT_SEGMENT_MAX) {
|
||||||
|
*why = "unit path segment is longer than eight characters";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (s[0] < 'a' || s[0] > 'z') {
|
||||||
|
*why = "unit path segment must start with a lowercase letter";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (i = 1; i < n; ++i) {
|
||||||
|
char c = s[i];
|
||||||
|
if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_') continue;
|
||||||
|
*why = "unit path segment may only contain lowercase letters, digits and '_'";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compare a dotted unit path against the source path it was read from.
|
||||||
|
`game.world.map` matches `.../game/world/map.fe` and nothing else. Only the
|
||||||
|
trailing segments are compared, since the leading part is the import root. */
|
||||||
|
static int path_matches(const char *unit, const char *source)
|
||||||
|
{
|
||||||
|
unsigned long ulen = strlen(unit), slen = strlen(source);
|
||||||
|
unsigned long u, s;
|
||||||
|
if (slen < 3 || strcmp(source + slen - 3, ".fe") != 0) return 0;
|
||||||
|
slen -= 3;
|
||||||
|
u = ulen;
|
||||||
|
s = slen;
|
||||||
|
while (u > 0) {
|
||||||
|
char uc, sc;
|
||||||
|
--u;
|
||||||
|
if (s == 0) return 0;
|
||||||
|
--s;
|
||||||
|
uc = unit[u];
|
||||||
|
sc = source[s];
|
||||||
|
if (uc == '.') {
|
||||||
|
if (sc != '/' && sc != '\\') return 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Host filesystems may be case-insensitive; the unit name is the
|
||||||
|
authority and is lowercase by 8.1, so fold the path side down. */
|
||||||
|
if (sc >= 'A' && sc <= 'Z') sc = (char)(sc - 'A' + 'a');
|
||||||
|
if (uc != sc) return 0;
|
||||||
|
}
|
||||||
|
/* What remains of the source path is the import root, and must end there. */
|
||||||
|
return s == 0 || source[s - 1] == '/' || source[s - 1] == '\\';
|
||||||
|
}
|
||||||
|
|
||||||
|
int fe_resolve_unit_identity(FeAst *ast, FeDiags *diags, const char *source_path)
|
||||||
|
{
|
||||||
|
FeNode *root = ast ? ast->root : 0;
|
||||||
|
const char *name, *why;
|
||||||
|
const char *seg;
|
||||||
|
unsigned long i, len;
|
||||||
|
int ok = 1;
|
||||||
|
|
||||||
|
if (!root || root->kind != FE_N_UNIT || !root->text) return 0;
|
||||||
|
name = root->text;
|
||||||
|
len = strlen(name);
|
||||||
|
|
||||||
|
seg = name;
|
||||||
|
for (i = 0; i <= len; ++i) {
|
||||||
|
if (i != len && name[i] != '.') continue;
|
||||||
|
if (!segment_ok(seg, (unsigned long)(name + i - seg), &why)) {
|
||||||
|
fe_diag_error(diags, root->loc, why);
|
||||||
|
ok = 0;
|
||||||
|
}
|
||||||
|
seg = name + i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok && source_path && !path_matches(name, source_path)) {
|
||||||
|
fe_diag_errorf(diags, root->loc,
|
||||||
|
"unit %s must be declared in a source file matching its path",
|
||||||
|
name);
|
||||||
|
ok = 0;
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef FE_RESOLVE_H
|
||||||
|
#define FE_RESOLVE_H
|
||||||
|
|
||||||
|
#include "ast.h"
|
||||||
|
#include "diag.h"
|
||||||
|
|
||||||
|
/* Unit-level resolution: identity, import bindings, and the unit graph.
|
||||||
|
This runs between parsing and semantic checking. It answers questions that
|
||||||
|
need more than one file -- what a unit is called, what it imports, and
|
||||||
|
whether those imports exist and terminate -- so that check.c can keep
|
||||||
|
looking at one function at a time. */
|
||||||
|
|
||||||
|
/* SPEC 8.1: each segment is ASCII lowercase, starts with a letter, continues
|
||||||
|
with letters, digits or '_', and is at most eight characters. The limit is
|
||||||
|
what makes a unit path map to a FAT/DOS 8.3 source path unambiguously. */
|
||||||
|
#define FE_UNIT_SEGMENT_MAX 8
|
||||||
|
|
||||||
|
/* Validate the `unit` declaration against SPEC 8.1, and against the file it was
|
||||||
|
read from: the path must match the dotted name, so `game.world.map` has to
|
||||||
|
come from `game/world/map.fe`. `source_path` may be null to skip that half.
|
||||||
|
Returns non-zero when the unit is well formed. */
|
||||||
|
int fe_resolve_unit_identity(FeAst *ast, FeDiags *diags, const char *source_path);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m4_bad_arity;
|
unit bad_ari;
|
||||||
|
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
@print("{} {}", 1);
|
@print("{} {}", 1);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m4_bad_buffer_writer;
|
unit bad_bufw;
|
||||||
|
|
||||||
fn main() -> void {
|
fn main() -> void {
|
||||||
var raw: [4]u8 = [0, 0, 0, 0];
|
var raw: [4]u8 = [0, 0, 0, 0];
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m4_bad_cls;
|
unit bad_cls;
|
||||||
|
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
@print("}", 1);
|
@print("}", 1);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m4_bad_many;
|
unit bad_many;
|
||||||
|
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
@print("{}", 1, 2);
|
@print("{}", 1, 2);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m4_bad_open;
|
unit bad_open;
|
||||||
|
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
@print("{", 1);
|
@print("{", 1);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m4_bad_runtime;
|
unit bad_run;
|
||||||
|
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
var fmt: str = "{}";
|
var fmt: str = "{}";
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m4_bad_try;
|
unit bad_try;
|
||||||
|
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
try @print("nope");
|
try @print("nope");
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m4_bad_type;
|
unit bad_type;
|
||||||
|
|
||||||
struct Point { x: i32, }
|
struct Point { x: i32, }
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m4_bad_verb;
|
unit bad_verb;
|
||||||
|
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
@print("{q}", 1);
|
@print("{q}", 1);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m4_bad_writer;
|
unit bad_writ;
|
||||||
|
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
var x: i32 = 0;
|
var x: i32 = 0;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m4_format;
|
unit ok_forma;
|
||||||
|
|
||||||
const FMT: str = "n={} hex={x} c={c} s={s} b={b} {{ok}}\n";
|
const FMT: str = "n={} hex={x} c={c} s={s} b={b} {{ok}}\n";
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m4_prop;
|
unit ok_prop;
|
||||||
|
|
||||||
pub fn propagate(w: io.Writer) -> !void {
|
pub fn propagate(w: io.Writer) -> !void {
|
||||||
try @fprint(w, "a{}b", 1);
|
try @fprint(w, "a{}b", 1);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m4_try_fprint;
|
unit ok_try_f;
|
||||||
|
|
||||||
fn main() -> !void {
|
fn main() -> !void {
|
||||||
var raw: [4]u8 = [0, 0, 0, 0];
|
var raw: [4]u8 = [0, 0, 0, 0];
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m5_bad_consuming_close;
|
unit bad_clos;
|
||||||
|
|
||||||
struct FileLike {
|
struct FileLike {
|
||||||
handle: i32,
|
handle: i32,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m5_bad_conditional;
|
unit bad_cond;
|
||||||
|
|
||||||
fn take(p: ^i32) -> void { mem.destroy(p); }
|
fn take(p: ^i32) -> void { mem.destroy(p); }
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m5_bad_double;
|
unit bad_dbl;
|
||||||
|
|
||||||
fn bad(p: ^i32) -> void {
|
fn bad(p: ^i32) -> void {
|
||||||
mem.destroy(p);
|
mem.destroy(p);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m5_bad_destroy;
|
unit bad_dest;
|
||||||
|
|
||||||
fn bad(x: i32) -> void {
|
fn bad(x: i32) -> void {
|
||||||
mem.destroy(x);
|
mem.destroy(x);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m5_bad_drop;
|
unit bad_drop;
|
||||||
|
|
||||||
struct Box {
|
struct Box {
|
||||||
value: i32,
|
value: i32,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m5_bad_loop_move;
|
unit bad_loop;
|
||||||
|
|
||||||
fn take(p: ^i32) -> void { mem.destroy(p); }
|
fn take(p: ^i32) -> void { mem.destroy(p); }
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m5_bad_move;
|
unit bad_move;
|
||||||
|
|
||||||
fn take(p: ^i32) -> void { mem.destroy(p); }
|
fn take(p: ^i32) -> void { mem.destroy(p); }
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m5_bad_projection_move;
|
unit bad_proj;
|
||||||
|
|
||||||
struct Holder { p: ^i32 }
|
struct Holder { p: ^i32 }
|
||||||
fn take(p: ^i32) -> void { mem.destroy(p); }
|
fn take(p: ^i32) -> void { mem.destroy(p); }
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m5_defer;
|
unit ok_defer;
|
||||||
|
|
||||||
pub fn cleanup(p: ^i32) -> void {
|
pub fn cleanup(p: ^i32) -> void {
|
||||||
defer { mem.destroy(p); }
|
defer { mem.destroy(p); }
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m5_owned;
|
unit ok_owned;
|
||||||
|
|
||||||
fn main() -> !void {
|
fn main() -> !void {
|
||||||
var p: ^i32 = try mem.create(0);
|
var p: ^i32 = try mem.create(0);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit keywords_and_builtins;
|
unit keybuilt;
|
||||||
|
|
||||||
pub fn demo() {
|
pub fn demo() {
|
||||||
let a = true and not false;
|
let a = true and not false;
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
// ERROR:logical operator
|
// ERROR:logical operator
|
||||||
unit old_logic;
|
unit logical;
|
||||||
fn main() { let x = true && false; }
|
fn main() { let x = true && false; }
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
// ERROR:expected ';'
|
// ERROR:expected ';'
|
||||||
unit broken;
|
unit misssemi;
|
||||||
fn main() { let x: i32 = 1 }
|
fn main() { let x: i32 = 1 }
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
// ERROR:unterminated block comment
|
// ERROR:unterminated block comment
|
||||||
unit broken;
|
unit unclcomm;
|
||||||
/* no ending delimiter
|
/* no ending delimiter
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
unit v012_forms;
|
unit v012form;
|
||||||
|
|
||||||
shared atomic var ticks: u16 = 0;
|
shared atomic var ticks: u16 = 0;
|
||||||
packed struct Packet {
|
packed struct Packet {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
unit bad_arity;
|
unit bad_ari;
|
||||||
|
|
||||||
fn add(a: i32, b: i32) -> i32 {
|
fn add(a: i32, b: i32) -> i32 {
|
||||||
return a + b;
|
return a + b;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit bad_assign;
|
unit bad_asgn;
|
||||||
|
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
let value: i32 = 1;
|
let value: i32 = 1;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit bad_condition;
|
unit bad_cond;
|
||||||
|
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
if 1 { return 0; }
|
if 1 { return 0; }
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m3_bad_mut_let;
|
unit bad_mlet;
|
||||||
|
|
||||||
fn bad() -> void {
|
fn bad() -> void {
|
||||||
var raw: [2]u8 = [1, 2];
|
var raw: [2]u8 = [1, 2];
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit bad_return;
|
unit bad_ret;
|
||||||
|
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
return true;
|
return true;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m3_bad_shared_write;
|
unit bad_shwr;
|
||||||
|
|
||||||
fn bad(s: []u8) -> void {
|
fn bad(s: []u8) -> void {
|
||||||
s[0] = 1;
|
s[0] = 1;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit bad_types;
|
unit bad_type;
|
||||||
|
|
||||||
fn add(a: i32, b: i32) -> i32 {
|
fn add(a: i32, b: i32) -> i32 {
|
||||||
return a + b;
|
return a + b;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit bad_uninit;
|
unit bad_unit;
|
||||||
|
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
var value: i32;
|
var value: i32;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit bad_unknown;
|
unit bad_unk;
|
||||||
|
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
return missing_name;
|
return missing_name;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit fail_m3_array;
|
unit badarr;
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
let a: [2]i32 = [1, true, 3];
|
let a: [2]i32 = [1, true, 3];
|
||||||
return a[0];
|
return a[0];
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
unit fail_m3_char;
|
unit badchar;
|
||||||
|
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
let u: u8 = 'A';
|
let u: u8 = 'A';
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
unit fail_m3_cycle;
|
unit badcycle;
|
||||||
|
|
||||||
struct A { b: B, }
|
struct A { b: B, }
|
||||||
struct B { a: A, }
|
struct B { a: A, }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
unit fail_m3_let_field;
|
unit badfield;
|
||||||
|
|
||||||
struct Point { x: i32, y: i32, }
|
struct Point { x: i32, y: i32, }
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
unit fail_m3_fields;
|
unit badfld;
|
||||||
struct Point { x: i32, y: i32, }
|
struct Point { x: i32, y: i32, }
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
let p: Point = Point{ x: 1 };
|
let p: Point = Point{ x: 1 };
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
unit fail_m3_let_index;
|
unit badindex;
|
||||||
|
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
let a: [2]i32 = [1, 2];
|
let a: [2]i32 = [1, 2];
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
unit fail_m3_match;
|
unit badmat;
|
||||||
enum Shape { Empty, Circle(i32), }
|
enum Shape { Empty, Circle(i32), }
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
match Shape.Empty { Empty => 0; }
|
match Shape.Empty { Empty => 0; }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
unit fail_m3_str;
|
unit badstr;
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
var text: str = "abc";
|
var text: str = "abc";
|
||||||
text[0] = 'z';
|
text[0] = 'z';
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m3_arrayctx;
|
unit ok_arra1;
|
||||||
|
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
let bytes: [3]u8 = [1, 2, 3];
|
let bytes: [3]u8 = [1, 2, 3];
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m3_array;
|
unit ok_array;
|
||||||
|
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
let a: [3]i32 = [1, 2, 3];
|
let a: [3]i32 = [1, 2, 3];
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit cast_while;
|
unit ok_castw;
|
||||||
|
|
||||||
pub fn main() -> i32 {
|
pub fn main() -> i32 {
|
||||||
var x: i16 = 0;
|
var x: i16 = 0;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m3_char;
|
unit ok_char;
|
||||||
|
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
let c: char = '\u0041';
|
let c: char = '\u0041';
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m3_enum;
|
unit ok_enum;
|
||||||
|
|
||||||
enum Shape { Empty, Circle(i32), Rect { w: i32, h: i32, }, }
|
enum Shape { Empty, Circle(i32), Rect { w: i32, h: i32, }, }
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m3_for;
|
unit ok_for;
|
||||||
|
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
var total: i32 = 0;
|
var total: i32 = 0;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit hello;
|
unit ok_hello;
|
||||||
|
|
||||||
fn add(a: i32, b: i32) -> i32 {
|
fn add(a: i32, b: i32) -> i32 {
|
||||||
return a + b;
|
return a + b;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m3_mutable;
|
unit ok_mutab;
|
||||||
|
|
||||||
fn takes_shared(s: []u8) -> u8 { return s[0]; }
|
fn takes_shared(s: []u8) -> u8 { return s[0]; }
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m3_nested;
|
unit ok_neste;
|
||||||
|
|
||||||
struct Outer { inner: Inner, }
|
struct Outer { inner: Inner, }
|
||||||
struct Inner { value: i32, }
|
struct Inner { value: i32, }
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit scopes;
|
unit ok_scope;
|
||||||
|
|
||||||
fn register(switch: i32) -> i32 {
|
fn register(switch: i32) -> i32 {
|
||||||
let auto: i32 = switch;
|
let auto: i32 = switch;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m3_str;
|
unit ok_str;
|
||||||
|
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
let text: str = "abc";
|
let text: str = "abc";
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
unit m3_struct;
|
unit ok_struc;
|
||||||
|
|
||||||
struct Point { x: i32, y: i32, }
|
struct Point { x: i32, y: i32, }
|
||||||
packed struct PackedPoint { x: u8, y: i32, }
|
packed struct PackedPoint { x: u8, y: i32, }
|
||||||
+1
-1
@@ -34,7 +34,7 @@ ROOT = Path(__file__).resolve().parent.parent
|
|||||||
FIXTURES = ROOT / "fec" / "tests"
|
FIXTURES = ROOT / "fec" / "tests"
|
||||||
WATCOM = ROOT / ".dosboxx" / "watcom"
|
WATCOM = ROOT / ".dosboxx" / "watcom"
|
||||||
SOURCES = ("arena", "diag", "lexer", "ast", "parser", "types", "m7", "own",
|
SOURCES = ("arena", "diag", "lexer", "ast", "parser", "types", "m7", "own",
|
||||||
"check", "driver")
|
"check", "resolve", "driver")
|
||||||
# Fixtures live here until there is a code generator to run them against.
|
# Fixtures live here until there is a code generator to run them against.
|
||||||
QUARANTINE = "pending-backend"
|
QUARANTINE = "pending-backend"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user