complete first draft of validator
This commit is contained in:
parent
9542dcf5e2
commit
eafe7a7fa9
12
src/main.rs
12
src/main.rs
|
@ -148,11 +148,11 @@ pub fn run(src: &'static str) {
|
|||
|
||||
let dummy_prelude = vec![];
|
||||
|
||||
let mut valxor = validator::Validator::new(&ast, span, &dummy_prelude);
|
||||
let mut v6or = validator::Validator::new(&ast, span, &dummy_prelude);
|
||||
|
||||
// valxor.validate();
|
||||
v6or.validate();
|
||||
|
||||
// dbg!(valxor);
|
||||
dbg!(v6or);
|
||||
|
||||
let mut ctx = prelude();
|
||||
ctx.ast = *
|
||||
|
@ -167,8 +167,10 @@ pub fn run(src: &'static str) {
|
|||
|
||||
pub fn main() {
|
||||
let src = "
|
||||
let #{:a (x, y), :b [1, 2, (a, b)]} = #{:a (1, 2), :b [1, 2, (7, 8)]}
|
||||
(x, y, a, b)
|
||||
let bar = :bar
|
||||
match :foo with {
|
||||
:foo -> bar
|
||||
}
|
||||
";
|
||||
run(src);
|
||||
// struct_scalpel::print_dissection_info::<value::Value>()
|
||||
|
|
188
src/validator.rs
188
src/validator.rs
|
@ -101,6 +101,21 @@ impl<'a> Validator<'a> {
|
|||
self.status.used_bindings.push(name);
|
||||
}
|
||||
|
||||
fn arity(&mut self) -> Arity {
|
||||
let Ast::MatchClause(pattern, ..) = self.ast else {
|
||||
unreachable!("internal Ludus error")
|
||||
};
|
||||
let (Ast::TuplePattern(members), _) = pattern.as_ref() else {
|
||||
unreachable!("internal Ludus error");
|
||||
};
|
||||
let last_member = members.last();
|
||||
match last_member {
|
||||
None => Arity::Fixed(0),
|
||||
Some((Ast::Splattern(..), _)) => Arity::Splat(members.len() as u8),
|
||||
Some(_) => Arity::Fixed(members.len() as u8),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate(&mut self) {
|
||||
use Ast::*;
|
||||
let root = self.ast;
|
||||
|
@ -297,22 +312,27 @@ impl<'a> Validator<'a> {
|
|||
self.validate();
|
||||
}
|
||||
}
|
||||
WhenClause(cond, body) => todo!(),
|
||||
When(clauses) => {
|
||||
// let tailpos = self.status.tail_position;
|
||||
// for (clause, _) in clauses {
|
||||
// self.status.tail_position = false;
|
||||
// let (expr, span) = clause.cond.clone();
|
||||
// self.ast = &expr;
|
||||
// self.span = span;
|
||||
// self.validate();
|
||||
WhenClause(cond, body) => {
|
||||
let tailpos = self.status.tail_position;
|
||||
self.status.tail_position = false;
|
||||
let (expr, span) = cond.as_ref();
|
||||
self.ast = expr;
|
||||
self.span = *span;
|
||||
self.validate();
|
||||
|
||||
// self.status.tail_position = tailpos;
|
||||
// let (expr, span) = clause.body;
|
||||
// self.ast = &expr;
|
||||
// self.span = span;
|
||||
// self.validate();
|
||||
// }
|
||||
self.status.tail_position = tailpos;
|
||||
let (expr, span) = body.as_ref();
|
||||
self.ast = expr;
|
||||
self.span = *span;
|
||||
self.validate();
|
||||
}
|
||||
When(clauses) => {
|
||||
for clause in clauses {
|
||||
let (expr, span) = clause;
|
||||
self.ast = expr;
|
||||
self.span = *span;
|
||||
self.validate();
|
||||
}
|
||||
}
|
||||
|
||||
// binding forms
|
||||
|
@ -339,14 +359,40 @@ impl<'a> Validator<'a> {
|
|||
self.span = *span;
|
||||
self.validate();
|
||||
}
|
||||
MatchClause(pattern, guard, body) => todo!(),
|
||||
Match(scrutinee, clauses) => {
|
||||
let (expr, span) = scrutinee.as_ref();
|
||||
MatchClause(pattern, guard, body) => {
|
||||
let to = self.locals.len();
|
||||
|
||||
let (patt, span) = pattern.as_ref();
|
||||
self.ast = patt;
|
||||
self.span = *span;
|
||||
self.validate();
|
||||
|
||||
if let Some((expr, span)) = guard.as_ref() {
|
||||
self.ast = expr;
|
||||
self.span = *span;
|
||||
self.validate();
|
||||
}
|
||||
|
||||
let (expr, span) = body.as_ref();
|
||||
self.ast = expr;
|
||||
self.span = *span;
|
||||
self.validate();
|
||||
|
||||
self.locals.truncate(to);
|
||||
}
|
||||
Match(scrutinee, clauses) => {
|
||||
let (expr, span) = scrutinee.as_ref();
|
||||
self.ast = expr;
|
||||
self.span = *span;
|
||||
self.validate();
|
||||
|
||||
for clause in clauses {
|
||||
let (expr, span) = clause;
|
||||
self.ast = expr;
|
||||
self.span = *span;
|
||||
self.validate();
|
||||
}
|
||||
}
|
||||
FnDeclaration(name) => {
|
||||
let tailpos = self.status.tail_position;
|
||||
self.status.tail_position = false;
|
||||
|
@ -367,11 +413,16 @@ impl<'a> Validator<'a> {
|
|||
}
|
||||
|
||||
let from = self.status.used_bindings.len();
|
||||
let arities = HashSet::new();
|
||||
let mut arities = HashSet::new();
|
||||
|
||||
for clause in clauses {
|
||||
// TODO: validate all parts of clauses
|
||||
let (expr, span) = clause;
|
||||
self.ast = expr;
|
||||
self.span = *span;
|
||||
// add clause arity to arities
|
||||
arities.insert(self.arity());
|
||||
self.validate();
|
||||
}
|
||||
|
||||
// this should be right
|
||||
|
@ -389,7 +440,11 @@ impl<'a> Validator<'a> {
|
|||
|
||||
let info = FnInfo::Defined(arities, closed_over);
|
||||
|
||||
self.define_fn(name.to_string(), info)
|
||||
let root_ptr: *const Ast = root;
|
||||
|
||||
self.fn_info.insert(root_ptr, info.clone());
|
||||
|
||||
self.define_fn(name.to_string(), info);
|
||||
}
|
||||
|
||||
Panic(msg) => {
|
||||
|
@ -448,7 +503,24 @@ impl<'a> Validator<'a> {
|
|||
self.status.in_loop = true;
|
||||
self.status.loop_arity = input.len() as u8;
|
||||
|
||||
// for clause in body {}
|
||||
for clause in body {
|
||||
let (expr, span) = clause;
|
||||
self.ast = expr;
|
||||
self.span = *span;
|
||||
match self.arity() {
|
||||
Arity::Fixed(clause_arity) => {
|
||||
if clause_arity != arity {
|
||||
self.err(format!("mismatched arity: expected {arity} arguments in `loop` clause; got {clause_arity}"))
|
||||
}
|
||||
}
|
||||
Arity::Splat(clause_arity) => {
|
||||
if clause_arity > arity {
|
||||
self.err(format!("mismathced arity: expected {arity} arguments in `loop` clause; this clause takes {clause_arity} or more"))
|
||||
}
|
||||
}
|
||||
};
|
||||
self.validate();
|
||||
}
|
||||
|
||||
self.status.in_loop = in_loop;
|
||||
self.status.loop_arity = arity;
|
||||
|
@ -484,13 +556,73 @@ impl<'a> Validator<'a> {
|
|||
self.bind(name.to_string());
|
||||
}
|
||||
},
|
||||
InterpolatedPattern(parts, _) => todo!(),
|
||||
AsPattern(name, r#type) => todo!(),
|
||||
Splattern(splatted) => todo!(),
|
||||
TuplePattern(tuple) => todo!(),
|
||||
ListPattern(list) => todo!(),
|
||||
PairPattern(key, patt) => todo!(),
|
||||
DictPattern(dict) => todo!(),
|
||||
InterpolatedPattern(parts, _) => {
|
||||
for (part, span) in parts {
|
||||
if let StringPart::Word(name) = part {
|
||||
self.span = *span;
|
||||
match self.bound(name) {
|
||||
Some(_) => self.err(format!("name `{name}` is already bound")),
|
||||
None => self.bind(name.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
AsPattern(name, r#type) => {
|
||||
match self.bound(name) {
|
||||
Some((name, _span, _)) => {
|
||||
self.err(format!("name `{name}` is already bound"));
|
||||
}
|
||||
None => {
|
||||
self.bind(name.to_string());
|
||||
}
|
||||
}
|
||||
let as_type = *r#type;
|
||||
match as_type {
|
||||
"nil" | "bool" | "number" | "keyword" | "string" | "tuple" | "dict"
|
||||
| "list" | "fn" | "box" => (),
|
||||
_ => self.err(format!("unknown type `:{as_type}`")),
|
||||
}
|
||||
}
|
||||
Splattern(splatted) => {
|
||||
if !self.status.last_term {
|
||||
self.err("splats in patterns must come last".to_string());
|
||||
}
|
||||
match splatted.as_ref() {
|
||||
(Ast::Placeholder, _) => (),
|
||||
(Ast::Word(name), span) => match self.bound(name) {
|
||||
Some(_) => {
|
||||
self.span = *span;
|
||||
self.err(format!("name `{name}` is already bound"))
|
||||
}
|
||||
None => self.bind(name.to_string()),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
TuplePattern(terms) | ListPattern(terms) | DictPattern(terms) => {
|
||||
if terms.is_empty() {
|
||||
return;
|
||||
}
|
||||
for term in terms.iter().take(terms.len() - 1) {
|
||||
let (patt, span) = term;
|
||||
self.ast = patt;
|
||||
self.span = *span;
|
||||
self.validate();
|
||||
}
|
||||
|
||||
self.status.last_term = true;
|
||||
let (patt, span) = terms.last().unwrap();
|
||||
self.ast = patt;
|
||||
self.span = *span;
|
||||
self.validate();
|
||||
self.status.last_term = false;
|
||||
}
|
||||
PairPattern(_, patt) => {
|
||||
let (patt, span) = patt.as_ref();
|
||||
self.ast = patt;
|
||||
self.span = *span;
|
||||
self.validate();
|
||||
}
|
||||
// terminals can never be invalid
|
||||
Nil | Boolean(_) | Number(_) | Keyword(_) | String(_) => (),
|
||||
// terminal patterns can never be invalid
|
||||
|
|
Loading…
Reference in New Issue
Block a user