use std::str::FromStr;
use std::collections::BTreeMap;
use crate::lexer::{self, Token};
use crate::parser::Line;
use crate::error;
use crate::terms::*;
use crate::rules::*;
use crate::terms::*;
use crate::numerics::*;
use crate::resource_block;
use super::ValueOrLogical;
use lalrpop_util::ParseError;
grammar(src_id: u64);
extern {
type Location = usize;
type Error = error::ParseError;
enum Token {
"Integer" => lexer::Token::Integer(<i64>),
"Float" => lexer::Token::Float(<f64>),
"String" => lexer::Token::String(<String>),
"Boolean" => lexer::Token::Boolean(<bool>),
"Symbol" => lexer::Token::Symbol(<Symbol>),
":" => lexer::Token::Colon, // :
"," => lexer::Token::Comma, // ,
"[" => lexer::Token::LB, // [
"]" => lexer::Token::RB, // ]
"(" => lexer::Token::LP, // (
")" => lexer::Token::RP, // )
"{" => lexer::Token::LCB, // {
"}" => lexer::Token::RCB, // }
"." => lexer::Token::Dot, // .
"new" => lexer::Token::New, // new
"!" => lexer::Token::Bang, // !
"*" => lexer::Token::Mul, // *
"/" => lexer::Token::Div, // /
"mod" => lexer::Token::Mod, // mod
"rem" => lexer::Token::Rem, // rem
"+" => lexer::Token::Add, // +
"-" => lexer::Token::Sub, // -
"==" => lexer::Token::Eq, // ==
"!=" => lexer::Token::Neq, // !=
"<=" => lexer::Token::Leq, // <=
">=" => lexer::Token::Geq, // >=
"<" => lexer::Token::Lt, // <
">" => lexer::Token::Gt, // >
"=" => lexer::Token::Unify, // =
":=" => lexer::Token::Assign, // :=
"|" => lexer::Token::Pipe, // |
";" => lexer::Token::SemiColon, // ;
"?=" => lexer::Token::Query, // ?=
"cut" => lexer::Token::Cut, // cut
"debug" => lexer::Token::Debug, // debug
"print" => lexer::Token::Print, // print
"in" => lexer::Token::In, // in
"forall" => lexer::Token::ForAll, // forall
"if" => lexer::Token::If, // if
"and" => lexer::Token::And, // and
"or" => lexer::Token::Or, // or
"not" => lexer::Token::Not, // not
"matches" => lexer::Token::Matches, // matches
"type" => lexer::Token::Type, // type
}
}
ResWord: String = {
"type" => "type".to_owned(),
"cut" => "cut".to_owned(),
"debug" => "debug".to_owned(),
"print" => "print".to_owned(),
"in" => "in".to_owned(),
"forall" => "forall".to_owned(),
"if" => "if".to_owned(),
"and" => "and".to_owned(),
"or" => "or".to_owned(),
"not" => "not".to_owned(),
"new" => "new".to_owned(),
"matches" => "matches".to_owned(),
}
// ****** Values ******* //
Integer: i64 = {
<"Integer">,
"+" <"Integer">,
"-" <i:"Integer"> => -i,
}
Float: f64 = {
<"Float">,
"+" <"Float">,
"-" <f:"Float"> => -f,
}
Number: Value = {
<Integer> => Value::Number(<>.into()),
<Float> => Value::Number(<>.into()),
};
PolarString: Value = <s:"String"> => {
Value::String(s)
};
Boolean: Value = <b:"Boolean"> => {
Value::Boolean(b)
};
Name: Symbol = <s:"Symbol"> => s;
Variable: Value = <n:Name> => {
Value::Variable(n)
};
RestVar: Value = "*" <n:Name> => {
Value::RestVariable(n)
};
Call: Value = {
// No args.
<name:Name> "(" ")" => {
let args = vec![];
let kwargs = None;
Value::Call(Call{name, args, kwargs})
},
// Positional args only.
<name:Name> "(" <mut args:(<ValExp> ",")*> <arg:ValExp> ")" => {
args.push(arg);
let kwargs = None;
Value::Call(Call{name, args, kwargs})
},
// Positional args + kwargs.
<name:Name> "(" <mut args:(<ValExp> ",")*> <fields:(<Kwargs<ValExp>>)>")" => {
let kwargs = Some(fields);
Value::Call(Call{name, args, kwargs})
}
};
DotCall: Value = {
<Call>,
// No args.
<w:ResWord> "(" ")" => {
let args = vec![];
let kwargs = None;
let name = Symbol(w);
Value::Call(Call{name, args, kwargs})
},
// Positional args only.
<w:ResWord> "(" <mut args:(<ValExp> ",")*> <arg:ValExp> ")" => {
args.push(arg);
let kwargs = None;
let name = Symbol(w);
Value::Call(Call{name, args, kwargs})
},
// Positional args + kwargs.
<w:ResWord> "(" <mut args:(<ValExp> ",")*> <fields:(<Kwargs<ValExp>>)>")" => {
let kwargs = Some(fields);
let name = Symbol(w);
Value::Call(Call{name, args, kwargs})
},
}
New: Value = {
"new" <call:Spanned<Call>> => {
let args = vec![call];
let op = Operation{operator: Operator::New, args};
Value::Expression(op)
},
};
Field<T>: (Symbol, Term) = {
<name:Name> ":" <value:T> => (name, value),
<w:ResWord> ":" <value:T> => (Symbol(w), value),
<name:Spanned<Variable>> => (name.value().as_symbol().unwrap().clone(), name),
}
Fields<T>: BTreeMap<Symbol, Term> = {
<field:Field<T>> => {
let mut fields = BTreeMap::new();
fields.insert(field.0, field.1);
fields
},
<loc:@L> <mut fields:Fields<T>> "," <tail:Field<T>?> =>? match tail {
None => Ok(fields),
Some((name, value)) => {
let existing = fields.insert(name.clone(), value);
if existing.is_some() {
return Err(ParseError::User { error: error::ParseError::DuplicateKey { loc, key: name.0 } })
}
Ok(fields)
}
}
};
Kwarg<T>: (Symbol, Term) = {
<name:Name> ":" <value:T> => (name, value),
<w:ResWord> ":" <value:T> => (Symbol(w), value),
}
Kwargs<T>: BTreeMap<Symbol, Term> = {
<field:Kwarg<T>> => {
let mut fields = BTreeMap::new();
fields.insert(field.0, field.1);
fields
},
<loc:@L> <mut fields:Kwargs<T>> "," <tail:Kwarg<T>?> =>? match tail {
None => Ok(fields),
Some((name, value)) => {
let existing = fields.insert(name.clone(), value);
if existing.is_some() {
return Err(ParseError::User { error: error::ParseError::DuplicateKey { loc, key: name.0 } })
}
Ok(fields)
}
}
};
Object<T>: Dictionary = {
"{" <fields:Fields<T>> "}" => {
Dictionary { fields }
},
"{" "}" => {
Dictionary {
fields: BTreeMap::new()
}
}
};
// ****** Dicts and literals ******* //
DictionaryTerm: Value = <fields:Object<ExpectValue<Exp5<"Term">>>> => {
Value::Dictionary(fields)
};
// Pattern dictionaries cannot contain any operators.
DictionaryPattern: Value = <fields:Object<ExpectValue<Exp9<"Pattern">>>> => {
Value::Pattern(Pattern::Dictionary(fields))
};
InstanceLiteralPattern: Value = <tag:Name> <fields:Object<ExpectValue<Exp9<"Pattern">>>> => {
let instance = InstanceLiteral{tag, fields};
Value::Pattern(Pattern::Instance(instance))
};
// ****** Operations ******* //
BuiltinOperator: Operator = {
"debug" => Operator::Debug,
"print" => Operator::Print,
};
BuiltinOperation: Value = {
<op:BuiltinOperator> "(" <mut args:(<ValExp> ",")*> <arg:ValExp?> ")" => {
match arg {
Some(arg) => args.push(arg),
None => ()
};
Value::Expression(Operation{operator: op, args: args})
},
"cut" => {
let args = vec![];
let op = Operation{operator: Operator::Cut, args};
Value::Expression(op)
},
"forall" "(" <arg1:LogExp> "," <arg2:LogExp> ")" => {
let args = vec![arg1, arg2];
let op = Operation{operator: Operator::ForAll, args};
Value::Expression(op)
},
};
RewritableOperator: Operator = {
"." => Operator::Dot,
"new" => Operator::New,
"in" => Operator::In,
};
RewrittenOperation: Value = {
<op:RewritableOperator> "(" <mut args:(<TermExp> ",")*> <arg:TermExp?> ")" => {
match arg {
Some(arg) => args.push(arg),
None => ()
};
Value::Expression(Operation{operator: op, args: args})
},
};
// ****** Expressions ******* //
// All ExpN & Exp productions are macros with one parameter. The parameter is the
// *string* "Term" or "Pattern" which controls whether the expression is over terms
// or patterns. (It is a string since we need to conditionally
// change the expression precedence allowed in patterns versus terms depending
// on the parameter type, and LALRPOP does not allow conditional macros on anything
// other than a string.
// Any term expression
TermExp: Term = {
<t:Exp1<"Term">> => match t {
ValueOrLogical::Value(t) | ValueOrLogical::Logical(t) | ValueOrLogical::Either(t) => {
t
}
}
}
// A value expression
ValExp: Term = {
<ExpectValue<Exp1<"Term">>>
}
// A logical expression
LogExp: Term = {
<ExpectLogical<Exp1<"Term">>>
}
// `ValueOrLogic` is used to do some simple parse-time
// checks for correctly formed expressions. For example,
// `x in y` is a logical expression, so it does
// not make sense to compare the result with a value.
// `x in y > 0` fails to parse because `A > B` expects
// A and B to be values, but `x in y` is a logical term.
// In Prolog, logicals would be a callable - things that can be called and fail or success
// Values are not callable. Together, values and logicals are terms.
IsValue<T>: ValueOrLogical = {
<Spanned<T>> => ValueOrLogical::Value(<>)
}
IsLogical<T>: ValueOrLogical = {
<Spanned<T>> => ValueOrLogical::Logical(<>)
}
IsAny<T>: ValueOrLogical = {
<Spanned<T>> => ValueOrLogical::Either(<>)
}
ExpectValue<T>: Term = {
<loc:@L> <term:T> =>? {
match term {
ValueOrLogical::Logical(term) => {
Err(ParseError::User { error: error::ParseError::WrongValueType { loc, term, expected: "value".to_string() } })
},
ValueOrLogical::Value(t) | ValueOrLogical::Either(t) => Ok(t)
}
}
}
ExpectLogical<T>: Term = {
<loc:@L> <term:T> =>? {
match term {
ValueOrLogical::Value(term) => {
Err(ParseError::User { error: error::ParseError::WrongValueType { loc, term, expected: "logical expression".to_string() } })
},
ValueOrLogical::Logical(t) | ValueOrLogical::Either(t) => Ok(t)
}
}
}
Exp10<T>: ValueOrLogical = {
<IsValue<Pattern>> if T == "Pattern",
<Value> if T == "Term",
"(" <Exp1<T>> ")", // "resets" the parsing
}
CallTerm: Value = {
<DotCall>,
<w:ResWord> => Value::String(w),
<s:"Symbol"> => Value::String(s.0),
// These provide ways to get keys that aren't
// expressable as `foo.bar`
"(" <Variable> ")",
"(" <PolarString> ")",
}
DotOp<T>: Value = {
<head:ExpectValue<Exp9<T>>> "." <call_term:Spanned<CallTerm>> => {
let args = vec![head, call_term];
let op = Operation{operator: Operator::Dot, args};
Value::Expression(op)
},
}
// .
Exp9<T>: ValueOrLogical = {
<IsAny<DotOp<T>>>,
<Exp10<T>>,
};
// in
InExp<T>: Value = {
<left:ExpectValue<Exp8<T>>> "in" <right:ExpectValue<Exp9<T>>> => {
let args = vec![left, right];
let op = Operation{operator: Operator::In, args};
Value::Expression(op)
},
}
Matches = {"matches"};
// matches
MatchExp<T>: Value = {
// Symbols on the RHS are treated as class names, just like in a specializers
<left:ExpectValue<Exp8<T>>> Matches <right:Spanned<Pattern>> => {
let right = if let Value::Variable(ref sym) = right.value() {
right.clone_with_value(Value::Pattern(Pattern::Instance(InstanceLiteral {
tag: sym.clone(),
fields: Dictionary::new()
})))
} else {
right
};
let args = vec![left, right];
let op = Operation{operator: Operator::Isa, args};
Value::Expression(op)
},
}
Exp8<T>: ValueOrLogical = {
<IsLogical<InExp<T>>>,
<IsLogical<MatchExp<T>>>,
<Exp9<T>>,
}
// * / mod rem
Op7: Operator = {
"*" => Operator::Mul,
"/" => Operator::Div,
"mod" => Operator::Mod,
"rem" => Operator::Rem,
}
MulExp<T>: Value = {
<exp7:ExpectValue<Exp7<T>>> <operator:Op7> <exp8:ExpectValue<Exp8<T>>> => {
let args = vec![exp7, exp8];
let op = Operation{operator, args};
Value::Expression(op)
},
}
Exp7<T>: ValueOrLogical = {
<IsValue<MulExp<T>>>,
<Exp8<T>>,
}
// + -
Op6: Operator = {
"+" => Operator::Add,
"-" => Operator::Sub,
}
AddExp<T>: Value = {
<exp6:ExpectValue<Exp6<T>>> <operator:Op6> <exp7:ExpectValue<Exp7<T>>> => {
let args = vec![exp6, exp7];
let op = Operation{operator, args};
Value::Expression(op)
},
}
Exp6<T>: ValueOrLogical = {
<IsValue<AddExp<T>>>,
<Exp7<T>>,
}
// == != <= < >= >
Op5: Operator = {
"==" => Operator::Eq,
"!=" => Operator::Neq,
"<=" => Operator::Leq,
">=" => Operator::Geq,
"<" => Operator::Lt,
">" => Operator::Gt,
}
CmpExp<T>: Value = {
<exp5:ExpectValue<Exp5<T>>> <operator:Op5> <exp6:ExpectValue<Exp6<T>>> => {
let args = vec![exp5, exp6];
let op = Operation{operator, args};
Value::Expression(op)
},
}
Exp5<T>: ValueOrLogical = {
<IsLogical<CmpExp<T>>>,
<Exp6<T>>,
}
// =, :=
UnifyExp<T>: Value = {
<exp4:ExpectValue<Exp4<T>>> "=" <exp5:ExpectValue<Exp5<T>>> => {
let args = vec![exp4, exp5];
let op = Operation{operator: Operator::Unify, args};
Value::Expression(op)
},
<variable:Spanned<Variable>> ":=" <exp5:ExpectValue<Exp5<T>>> => {
let args = vec![variable, exp5];
let op = Operation{operator: Operator::Assign, args};
Value::Expression(op)
},
}
Exp4<T>: ValueOrLogical = {
<IsLogical<UnifyExp<T>>>,
<Exp5<T>>,
}
// !
Not = {"not"};
NotExp<T>: Value = {
Not <exp4:ExpectLogical<Exp4<T>>> => {
let args = vec![exp4];
let op = Operation{operator: Operator::Not, args};
Value::Expression(op)
},
}
Exp3<T>: ValueOrLogical = {
<IsLogical<NotExp<T>>>,
<Exp4<T>>,
}
And = {"and"};
AndExp<T>: Value = {
<head:ExpectLogical<Exp3<T>>> And <mut tail:ExpectLogical<Exp2<T>>> => {
let args = match &mut tail.value() {
Value::Expression(Operation{operator: Operator::And, args: tail_args}) => {
let mut args = vec![head];
args.append(&mut tail_args.clone());
args
}
_ => {
vec![head, tail]
}
};
let op = Operation{operator: Operator::And, args};
Value::Expression(op)
},
}
Exp2<T>: ValueOrLogical = {
<IsLogical<AndExp<T>>>,
<Exp3<T>>,
}
Or = {"or"};
OrExp<T>: Value = {
<head:ExpectLogical<Exp2<T>>> Or <mut tail:ExpectLogical<Exp1<T>>> => {
let args = match &mut tail.value() {
Value::Expression(Operation{operator: Operator::Or, args: tail_args}) => {
let mut args = vec![head];
args.append(&mut tail_args.clone());
args
}
_ => {
vec![head, tail]
}
};
let op = Operation{operator: Operator::Or, args};
Value::Expression(op)
},
}
Exp1<T>: ValueOrLogical = {
<IsLogical<OrExp<T>>>,
<Exp2<T>>,
}
ListTerms<T>: Vec<Term> = {
<ExpectValue<Exp6<T>>> => vec![<>],
<mut list:ListTerms<T>> "," <tail:ExpectValue<Exp6<T>>?> => {
match tail {
None => list,
Some(tail) => {
list.push(tail);
list
}
}
},
}
List<T>: Value = {
"[" "]" => Value::List(vec![]),
"[" <Spanned<RestVar>> "]" => Value::List(vec![<>]),
"[" <ListTerms<T>> "]" => Value::List(<>),
"[" <mut terms:ListTerms<T>> "," <rest:Spanned<RestVar>> "]" => {
terms.push(rest);
Value::List(terms)
}
}
Pattern: Value = {
<Number>,
<PolarString>,
<Boolean>,
<Variable>,
<DictionaryPattern>,
<InstanceLiteralPattern>,
<List<"Pattern">>,
};
Value: ValueOrLogical = {
<IsLogical<BuiltinOperation>>,
<IsAny<Boolean>>,
<IsAny<Variable>>,
<IsLogical<Call>>,
<IsValue<New>>,
<IsValue<List<"Term">>>,
<IsValue<Number>>,
<IsValue<PolarString>>,
<IsValue<DictionaryTerm>>,
<IsLogical<RewrittenOperation>>,
};
// ****** Terms + Patterns ******* //
Spanned<T>: Term = <start:@L> <value:T> <end:@R> => Term::new_from_parser(src_id, start, end, value);
pub Term = TermExp;
// ****** Rules + Lines ******* //
ParameterList: Vec<Parameter> = {
<param:Parameter> => vec![param],
<mut list:ParameterList> "," <param:Parameter> => {
list.push(param);
list
},
};
Parameter: Parameter = {
<parameter:ExpectValue<Exp6<"Term">>> => {
Parameter{parameter, specializer: None}
},
<parameter:Spanned<Variable>> ":" <specializer:Spanned<Pattern>> => {
if let Value::Variable(class_name) = specializer.value() {
let fields = BTreeMap::new();
let instance_literal = InstanceLiteral{tag: class_name.clone(), fields: Dictionary{fields}};
Parameter {
parameter,
specializer: Some(specializer.clone_with_value(Value::Pattern(Pattern::Instance(instance_literal)))),
}
} else {
Parameter{parameter, specializer: Some(specializer)}
}
},
};
RuleHead: (Symbol, Vec<Parameter>) = {
<name:Name> "(" ")" => {
(name, vec![])
},
<name:Name> "(" <params:ParameterList> ")" => {
(name, params)
}
};
Define = {"if"};
BodilessRule: Rule = <start_head:@L> <head:RuleHead> <start:@L> <end:@R> ";" => {
let (name, params) = head;
let op = Operation{operator: Operator::And, args: vec![]};
let body = Term::new_from_parser(src_id, start, end, Value::Expression(op));
Rule::new_from_parser(src_id, start_head, start, name, params, body)
};
Rule: Rule = {
<BodilessRule>,
<start_head:@L> <head:RuleHead> <end_head:@R> Define <body:TermExp> ";" => {
let (name, params) = head;
let body = match body.value() {
Value::Expression(Operation{operator: Operator::And, ..}) => {
body
},
_ => {
let op = Operation{operator: Operator::And, args: vec![body.clone()]};
body.clone_with_value(Value::Expression(op))
}
};
Rule::new_from_parser(src_id, start_head, end_head, name, params, body)
}
}
RuleType: Rule = "type" <BodilessRule>;
pub(crate) Rules: Vec<Rule> = <Rule*>;
// TODO(gj): combine this with ListTerms/List?
StringListTerms: Vec<Term> = {
<Spanned<PolarString>> => vec![<>],
<mut list:StringListTerms> "," <tail:Spanned<PolarString>?> => {
if let Some(tail) = tail {
list.push(tail);
}
list
},
}
StringList: Value = {
"[" "]" => Value::List(vec![]),
"[" <StringListTerms> "]" => Value::List(<>),
}
DeclarationValue: Value = {
<StringList> => <>,
<Object<Spanned<Variable>>> => Value::Dictionary(<>),
};
Declaration: resource_block::Production = <Spanned<Variable>> "=" <Spanned<DeclarationValue>> ";" => resource_block::Production::Declaration((<>));
OnRelation: (Term, Term) = <Spanned<Variable>> <Spanned<PolarString>> => (<>);
ShorthandRuleBody: (Term, Option<(Term, Term)>) = <implier:Spanned<PolarString>> <relation:OnRelation?> ";" => (<>);
ShorthandRule: resource_block::Production = <head:Spanned<PolarString>> Define <body:ShorthandRuleBody> => resource_block::Production::ShorthandRule(<>);
ResourceBlockProduction: resource_block::Production = {
<Declaration> => <>,
<ShorthandRule> => <>,
};
ResourceBlockProductions: Vec<resource_block::Production> = <ResourceBlockProduction*>;
Line: Line = {
<Rule> => Line::Rule(<>),
<RuleType> => Line::RuleType(<>),
"?=" <TermExp> ";" => Line::Query(<>),
<start:@L> <keyword:Spanned<Variable>?> <resource:Variable> "{" <productions:ResourceBlockProductions> "}" <end:@R> => {
let resource = Term::new_from_parser(src_id, start, end, resource);
Line::ResourceBlock { keyword, resource, productions }
}
}
pub Lines: Vec<Line> = <Line*>;