If exprs, patterns
This commit is contained in:
parent
8e19b7c39d
commit
6a318257d6
@ -239,7 +239,7 @@ pub struct ConditionArm {
|
|||||||
pub enum Condition {
|
pub enum Condition {
|
||||||
Pattern(Pattern),
|
Pattern(Pattern),
|
||||||
TruncatedOp(BinOp, Expression),
|
TruncatedOp(BinOp, Expression),
|
||||||
Expression(Expression),
|
//Expression(Expression), //I'm pretty sure I don't actually want this
|
||||||
Else,
|
Else,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,9 +166,6 @@ pub fn walk_if_expr_body<V: ASTVisitor>(v: &mut V, body: &IfExpressionBody) {
|
|||||||
Condition::TruncatedOp(ref _binop, ref expr) => {
|
Condition::TruncatedOp(ref _binop, ref expr) => {
|
||||||
walk_expression(v, expr);
|
walk_expression(v, expr);
|
||||||
}
|
}
|
||||||
Condition::Expression(ref expr) => {
|
|
||||||
walk_expression(v, expr);
|
|
||||||
}
|
|
||||||
Condition::Else => (),
|
Condition::Else => (),
|
||||||
}
|
}
|
||||||
if let Some(ref guard) = arm.guard {
|
if let Some(ref guard) = arm.guard {
|
||||||
|
@ -168,8 +168,8 @@
|
|||||||
//!
|
//!
|
||||||
//! module := 'module' IDENTIFIER '{' statement* '}'
|
//! module := 'module' IDENTIFIER '{' statement* '}'
|
||||||
//! ```
|
//! ```
|
||||||
mod test;
|
|
||||||
mod new;
|
mod new;
|
||||||
|
mod test;
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@ -1048,7 +1048,8 @@ impl Parser {
|
|||||||
let expr = self.expression()?;
|
let expr = self.expression()?;
|
||||||
Condition::TruncatedOp(op, expr)
|
Condition::TruncatedOp(op, expr)
|
||||||
}
|
}
|
||||||
_ => Condition::Expression(self.expression()?),
|
//_ => Condition::Expression(self.expression()?),
|
||||||
|
_ => panic!(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,42 +1,11 @@
|
|||||||
use crate::ast::*;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Debug)]
|
use crate::ast::*;
|
||||||
struct BinopSequence {
|
|
||||||
first: ExpressionKind,
|
|
||||||
next: Vec<(BinOp, ExpressionKind)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BinopSequence {
|
|
||||||
fn do_precedence(self) -> ExpressionKind {
|
|
||||||
fn helper(precedence: i32, lhs: ExpressionKind, rest: &mut Vec<(BinOp, ExpressionKind)>) -> Expression {
|
|
||||||
let mut lhs = Expression::new(Default::default(), lhs);
|
|
||||||
loop {
|
|
||||||
let (next_op, next_rhs) = match rest.pop() {
|
|
||||||
Some((a, b)) => (a, b),
|
|
||||||
None => break,
|
|
||||||
};
|
|
||||||
let new_precedence = next_op.get_precedence();
|
|
||||||
if precedence >= new_precedence {
|
|
||||||
rest.push((next_op, next_rhs));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
let rhs = helper(new_precedence, next_rhs, rest);
|
|
||||||
lhs = Expression::new(Default::default(),
|
|
||||||
ExpressionKind::BinExp(next_op, Box::new(lhs), Box::new(rhs))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
lhs
|
|
||||||
}
|
|
||||||
let mut as_stack = self.next.into_iter().rev().collect();
|
|
||||||
helper(BinOp::min_precedence(), self.first, &mut as_stack).kind
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
peg::parser! {
|
peg::parser! {
|
||||||
pub grammar schala_parser() for str {
|
pub grammar schala_parser() for str {
|
||||||
|
|
||||||
rule whitespace() = [' ' | '\t']*
|
rule whitespace() = [' ' | '\t' | '\n']*
|
||||||
|
|
||||||
rule _ = quiet!{ whitespace() }
|
rule _ = quiet!{ whitespace() }
|
||||||
|
|
||||||
@ -46,18 +15,20 @@ peg::parser! {
|
|||||||
rule delimiter() = ";" / "\n"
|
rule delimiter() = ";" / "\n"
|
||||||
|
|
||||||
rule statement() -> Statement =
|
rule statement() -> Statement =
|
||||||
expr:expression() { Statement {
|
_ expr:expression() { Statement {
|
||||||
id: Default::default(), location: Default::default(), kind: StatementKind::Expression(expr) }
|
id: Default::default(), location: Default::default(), kind: StatementKind::Expression(expr) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rule block() -> Block = "{" items:(statement() ** delimiter()) "}" { items.into() }
|
||||||
|
|
||||||
pub rule expression() -> Expression =
|
pub rule expression() -> Expression =
|
||||||
kind:expression_kind() { Expression { id: Default::default(), type_anno: None, kind: kind } }
|
_ kind:expression_kind() { Expression { id: Default::default(), type_anno: None, kind: kind } }
|
||||||
|
|
||||||
rule expression_kind() -> ExpressionKind =
|
rule expression_kind() -> ExpressionKind =
|
||||||
precedence_expr()
|
precedence_expr()
|
||||||
|
|
||||||
rule precedence_expr() -> ExpressionKind =
|
rule precedence_expr() -> ExpressionKind =
|
||||||
first:primary() _ next:(precedence_continuation())* {
|
first:prefix_expr() _ next:(precedence_continuation())* {
|
||||||
let next = next.into_iter().map(|(sigil, expr)| (BinOp::from_sigil(sigil), expr)).collect();
|
let next = next.into_iter().map(|(sigil, expr)| (BinOp::from_sigil(sigil), expr)).collect();
|
||||||
BinopSequence { first, next }.do_precedence()
|
BinopSequence { first, next }.do_precedence()
|
||||||
}
|
}
|
||||||
@ -65,13 +36,142 @@ peg::parser! {
|
|||||||
rule precedence_continuation() -> (&'input str, ExpressionKind) =
|
rule precedence_continuation() -> (&'input str, ExpressionKind) =
|
||||||
op:operator() _ expr:primary() _ { (op, expr) }
|
op:operator() _ expr:primary() _ { (op, expr) }
|
||||||
|
|
||||||
//TODO maybe make this more complex
|
rule prefix_expr() -> ExpressionKind =
|
||||||
|
prefix:prefix()? expr:extended_expr() {
|
||||||
|
if let Some(p) = prefix {
|
||||||
|
let expr = Expression::new(Default::default(), expr);
|
||||||
|
let prefix = PrefixOp::from_sigil(p);
|
||||||
|
ExpressionKind::PrefixExp(prefix, Box::new(expr))
|
||||||
|
} else {
|
||||||
|
expr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rule prefix() -> &'input str =
|
||||||
|
$(['+' | '-' | '!' ])
|
||||||
|
|
||||||
|
//TODO make the definition of operators more complex
|
||||||
rule operator() -> &'input str =
|
rule operator() -> &'input str =
|
||||||
$( ['+' | '-' | '*' | '/' | '%' | '<' | '>' | '=' | '!' | '$' | '&' | '?' | '^' | '`']+ )
|
quiet!{$( ['+' | '-' | '*' | '/' | '%' | '<' | '>' | '=' | '!' | '$' | '&' | '|' | '?' | '^' | '`']+ )} /
|
||||||
|
expected!("operator")
|
||||||
|
|
||||||
|
rule extended_expr() -> ExpressionKind =
|
||||||
|
primary()
|
||||||
|
|
||||||
rule primary() -> ExpressionKind =
|
rule primary() -> ExpressionKind =
|
||||||
float_literal() / nat_literal() / bool_literal() / string_literal() / paren_expr() /
|
float_literal() / nat_literal() / bool_literal() / string_literal() / paren_expr() /
|
||||||
list_expr()
|
list_expr() / if_expr() / identifier_expr()
|
||||||
|
|
||||||
|
rule identifier_expr() -> ExpressionKind =
|
||||||
|
named_struct() / qn:qualified_identifier() { ExpressionKind::Value(qn) }
|
||||||
|
|
||||||
|
rule named_struct() -> ExpressionKind =
|
||||||
|
name:qualified_identifier() _ fields:record_block() {
|
||||||
|
ExpressionKind::NamedStruct {
|
||||||
|
name,
|
||||||
|
fields: fields.into_iter().map(|(n, exp)| (Rc::new(n.to_string()), exp)).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//TODO anonymous structs, update syntax for structs
|
||||||
|
rule record_block() -> Vec<(&'input str, Expression)> =
|
||||||
|
"{" _ entries:(record_entry() ** ",") _ "}" { entries }
|
||||||
|
|
||||||
|
rule record_entry() -> (&'input str, Expression) =
|
||||||
|
_ name:identifier() _ ":" _ expr:expression() _ { (name, expr) }
|
||||||
|
|
||||||
|
rule qualified_identifier() -> QualifiedName =
|
||||||
|
names:(identifier() ++ "::") { QualifiedName { id: Default::default(), components: names.into_iter().map(|name| Rc::new(name.to_string())).collect() } }
|
||||||
|
|
||||||
|
//TODO improve the definition of identifiers
|
||||||
|
rule identifier() -> &'input str =
|
||||||
|
$(['a'..='z' | 'A'..='Z' | '_'] ['a'..='z' | 'A'..='Z' | '0'..='9' | '_']*)
|
||||||
|
|
||||||
|
|
||||||
|
rule if_expr() -> ExpressionKind =
|
||||||
|
"if" _ discriminator:(expression()?) _ body:if_expr_body() {
|
||||||
|
ExpressionKind::IfExpression {
|
||||||
|
discriminator: discriminator.map(Box::new),
|
||||||
|
body: Box::new(body),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rule if_expr_body() -> IfExpressionBody =
|
||||||
|
cond_block() / simple_pattern_match() / simple_conditional()
|
||||||
|
|
||||||
|
rule simple_conditional() -> IfExpressionBody =
|
||||||
|
"then" _ then_case:expr_or_block() _ else_case:else_case() {
|
||||||
|
IfExpressionBody::SimpleConditional { then_case, else_case }
|
||||||
|
}
|
||||||
|
|
||||||
|
rule simple_pattern_match() -> IfExpressionBody =
|
||||||
|
"is" _ pattern:pattern() _ "then" _ then_case:expr_or_block() _ else_case:else_case() {
|
||||||
|
IfExpressionBody::SimplePatternMatch { pattern, then_case, else_case }
|
||||||
|
}
|
||||||
|
|
||||||
|
rule cond_block() -> IfExpressionBody =
|
||||||
|
"{" _ cond_arms:(cond_arm() ++ ",") _ "}" { IfExpressionBody::CondList(cond_arms) }
|
||||||
|
|
||||||
|
rule cond_arm() -> ConditionArm =
|
||||||
|
_ "else" _ body:expr_or_block() { ConditionArm { condition: Condition::Else, guard: None, body } } /
|
||||||
|
_ condition:condition() _ guard:condition_guard() _ "then" _ body:expr_or_block()
|
||||||
|
{ ConditionArm { condition, guard, body } }
|
||||||
|
|
||||||
|
rule condition() -> Condition =
|
||||||
|
"is" _ pat:pattern() { Condition::Pattern(pat) } /
|
||||||
|
op:operator() _ expr:expression() { Condition::TruncatedOp(BinOp::from_sigil(op), expr) }
|
||||||
|
|
||||||
|
rule condition_guard() -> Option<Expression> =
|
||||||
|
("if" _ expr:expression() { expr } )?
|
||||||
|
|
||||||
|
|
||||||
|
rule expr_or_block() -> Block = block() / ex:expression() {
|
||||||
|
Statement {
|
||||||
|
id: Default::default(), location: Default::default(),
|
||||||
|
kind: StatementKind::Expression(ex)
|
||||||
|
}.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
rule else_case() -> Option<Block> =
|
||||||
|
("else" _ eorb:expr_or_block() { eorb })?
|
||||||
|
|
||||||
|
rule pattern() -> Pattern =
|
||||||
|
"(" _ variants:(pattern() ++ ",") _ ")" { Pattern::TuplePattern(variants) } /
|
||||||
|
_ pat:simple_pattern() { pat }
|
||||||
|
|
||||||
|
rule simple_pattern() -> Pattern =
|
||||||
|
pattern_literal() /
|
||||||
|
qn:qualified_identifier() "(" members:(pattern() ** ",") ")" {
|
||||||
|
Pattern::TupleStruct(qn, members)
|
||||||
|
} /
|
||||||
|
qn:qualified_identifier() _ "{" _ items:(record_pattern_entry() ** ",") "}" _ {
|
||||||
|
let items = items.into_iter().map(|(name, pat)| (Rc::new(name.to_string()), pat)).collect();
|
||||||
|
Pattern::Record(qn, items)
|
||||||
|
} /
|
||||||
|
qn:qualified_identifier() { Pattern::VarOrName(qn) }
|
||||||
|
|
||||||
|
rule record_pattern_entry() -> (&'input str, Pattern) =
|
||||||
|
_ name:identifier() _ ":" _ pat:pattern() _ { (name, pat) } /
|
||||||
|
_ name:identifier() _ {
|
||||||
|
let qn = QualifiedName {
|
||||||
|
id: Default::default(),
|
||||||
|
components: vec![Rc::new(name.to_string())],
|
||||||
|
};
|
||||||
|
(name, Pattern::VarOrName(qn))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rule pattern_literal() -> Pattern =
|
||||||
|
"true" { Pattern::Literal(PatternLiteral::BoolPattern(true)) } /
|
||||||
|
"false" { Pattern::Literal(PatternLiteral::BoolPattern(false)) } /
|
||||||
|
s:bare_string_literal() { Pattern::Literal(PatternLiteral::StringPattern(Rc::new(s.to_string()))) } /
|
||||||
|
sign:("-"?) num:nat_literal() {
|
||||||
|
let neg = sign.is_some();
|
||||||
|
Pattern::Literal(PatternLiteral::NumPattern { neg, num })
|
||||||
|
} /
|
||||||
|
"_" { Pattern::Ignored }
|
||||||
|
|
||||||
|
|
||||||
rule list_expr() -> ExpressionKind =
|
rule list_expr() -> ExpressionKind =
|
||||||
"[" exprs:(expression() ** ",") "]" {
|
"[" exprs:(expression() ** ",") "]" {
|
||||||
@ -88,9 +188,12 @@ peg::parser! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO string escapes, prefixes
|
|
||||||
rule string_literal() -> ExpressionKind =
|
rule string_literal() -> ExpressionKind =
|
||||||
"\"" items:$([^ '"' ]*) "\"" { ExpressionKind::StringLiteral(Rc::new(items.to_string())) }
|
s:bare_string_literal(){ ExpressionKind::StringLiteral(Rc::new(s.to_string())) }
|
||||||
|
|
||||||
|
//TODO string escapes, prefixes
|
||||||
|
rule bare_string_literal() -> &'input str =
|
||||||
|
"\"" items:$([^ '"' ]*) "\"" { items }
|
||||||
|
|
||||||
rule bool_literal() -> ExpressionKind =
|
rule bool_literal() -> ExpressionKind =
|
||||||
"true" { ExpressionKind::BoolLiteral(true) } / "false" { ExpressionKind::BoolLiteral(false) }
|
"true" { ExpressionKind::BoolLiteral(true) } / "false" { ExpressionKind::BoolLiteral(false) }
|
||||||
@ -121,7 +224,7 @@ peg::parser! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_binary(digits: &str/*, tok: Token*/) -> /*ParseResult<u64>*/ u64 {
|
fn parse_binary(digits: &str /*, tok: Token*/) -> u64 {
|
||||||
let mut result: u64 = 0;
|
let mut result: u64 = 0;
|
||||||
let mut multiplier = 1;
|
let mut multiplier = 1;
|
||||||
for d in digits.chars().rev() {
|
for d in digits.chars().rev() {
|
||||||
@ -129,11 +232,13 @@ fn parse_binary(digits: &str/*, tok: Token*/) -> /*ParseResult<u64>*/ u64 {
|
|||||||
'1' => result += multiplier,
|
'1' => result += multiplier,
|
||||||
'0' => (),
|
'0' => (),
|
||||||
'_' => continue,
|
'_' => continue,
|
||||||
_ => unreachable!()
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
multiplier = match multiplier.checked_mul(2) {
|
multiplier = match multiplier.checked_mul(2) {
|
||||||
Some(m) => m,
|
Some(m) => m,
|
||||||
None => /*return ParseError::new_with_token("This binary expression will overflow", tok),*/ panic!(),
|
None =>
|
||||||
|
/*return ParseError::new_with_token("This binary expression will overflow", tok),*/
|
||||||
|
panic!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Ok(result)
|
//Ok(result)
|
||||||
@ -154,89 +259,45 @@ fn parse_hex(digits: &str) -> u64 {
|
|||||||
}
|
}
|
||||||
multiplier = match multiplier.checked_mul(16) {
|
multiplier = match multiplier.checked_mul(16) {
|
||||||
Some(m) => m,
|
Some(m) => m,
|
||||||
None => panic!()
|
None => panic!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
#[cfg(test)]
|
struct BinopSequence {
|
||||||
mod test {
|
first: ExpressionKind,
|
||||||
use super::*;
|
next: Vec<(BinOp, ExpressionKind)>,
|
||||||
use pretty_assertions::assert_eq;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn new_parser() {
|
|
||||||
let parsed = schala_parser::expression("4");
|
|
||||||
assert_eq!(parsed.unwrap(), Expression { id: Default::default(), type_anno: None, kind: ExpressionKind::NatLiteral(4) });
|
|
||||||
|
|
||||||
let parsed = schala_parser::program("56.1");
|
|
||||||
if let Err(ref err) = parsed {
|
|
||||||
println!("{}", err);
|
|
||||||
}
|
|
||||||
assert_eq!(parsed.unwrap(), AST {
|
|
||||||
id: Default::default(), statements: vec![
|
|
||||||
Statement {
|
|
||||||
id: Default::default(),
|
|
||||||
location: Default::default(),
|
|
||||||
kind: StatementKind::Expression(Expression { id: Default::default(), type_anno: None, kind:
|
|
||||||
ExpressionKind::FloatLiteral(56.1) })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
].into() });
|
impl BinopSequence {
|
||||||
|
fn do_precedence(self) -> ExpressionKind {
|
||||||
let parsed = schala_parser::program("1;2\n5\n(1.1,false)");
|
fn helper(
|
||||||
if let Err(ref err) = parsed {
|
precedence: i32,
|
||||||
println!("{}", err);
|
lhs: ExpressionKind,
|
||||||
|
rest: &mut Vec<(BinOp, ExpressionKind)>,
|
||||||
|
) -> Expression {
|
||||||
|
let mut lhs = Expression::new(Default::default(), lhs);
|
||||||
|
loop {
|
||||||
|
let (next_op, next_rhs) = match rest.pop() {
|
||||||
|
Some((a, b)) => (a, b),
|
||||||
|
None => break,
|
||||||
|
};
|
||||||
|
let new_precedence = next_op.get_precedence();
|
||||||
|
if precedence >= new_precedence {
|
||||||
|
rest.push((next_op, next_rhs));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
assert_eq!(parsed.unwrap(), AST {
|
let rhs = helper(new_precedence, next_rhs, rest);
|
||||||
id: Default::default(), statements: vec![
|
lhs = Expression::new(
|
||||||
Statement {
|
Default::default(),
|
||||||
id: Default::default(),
|
ExpressionKind::BinExp(next_op, Box::new(lhs), Box::new(rhs)),
|
||||||
location: Default::default(),
|
);
|
||||||
kind: StatementKind::Expression(Expression { id: Default::default(), type_anno: None, kind:
|
|
||||||
ExpressionKind::NatLiteral(1) })
|
|
||||||
},
|
|
||||||
Statement {
|
|
||||||
id: Default::default(),
|
|
||||||
location: Default::default(),
|
|
||||||
kind: StatementKind::Expression(Expression { id: Default::default(), type_anno: None, kind:
|
|
||||||
ExpressionKind::NatLiteral(2) })
|
|
||||||
},
|
|
||||||
Statement {
|
|
||||||
id: Default::default(),
|
|
||||||
location: Default::default(),
|
|
||||||
kind: StatementKind::Expression(Expression { id: Default::default(), type_anno: None, kind:
|
|
||||||
ExpressionKind::NatLiteral(5) })
|
|
||||||
},
|
|
||||||
Statement {
|
|
||||||
id: Default::default(),
|
|
||||||
location: Default::default(),
|
|
||||||
kind: StatementKind::Expression(Expression { id: Default::default(), type_anno: None, kind:
|
|
||||||
ExpressionKind::TupleLiteral(vec![Expression{
|
|
||||||
id: Default::default(),
|
|
||||||
type_anno: None,
|
|
||||||
kind: ExpressionKind::FloatLiteral(1.1),
|
|
||||||
},
|
|
||||||
Expression {
|
|
||||||
id: Default::default(),
|
|
||||||
type_anno: None,
|
|
||||||
kind: ExpressionKind::BoolLiteral(false),
|
|
||||||
}]
|
|
||||||
|
|
||||||
) })
|
|
||||||
}
|
}
|
||||||
|
lhs
|
||||||
].into() });
|
}
|
||||||
|
let mut as_stack = self.next.into_iter().rev().collect();
|
||||||
/*
|
helper(BinOp::min_precedence(), self.first, &mut as_stack).kind
|
||||||
let parsed = schala_parser::expression("quincy");
|
|
||||||
println!("{:?}", parsed.unwrap_err());
|
|
||||||
|
|
||||||
assert_eq!(1, 2);
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,8 @@ use std::{fmt::Write, rc::Rc};
|
|||||||
|
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
use super::{tokenize, ParseResult, Parser};
|
use super::{new::schala_parser, tokenize, ParseResult, Parser};
|
||||||
use crate::{ast::*, tokenizing::Location};
|
use crate::{ast::*, tokenizing::Location};
|
||||||
use super::new::schala_parser;
|
|
||||||
|
|
||||||
fn rc(s: &str) -> Rc<String> {
|
fn rc(s: &str) -> Rc<String> {
|
||||||
Rc::new(s.to_owned())
|
Rc::new(s.to_owned())
|
||||||
@ -108,6 +107,18 @@ macro_rules! assert_ast {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! assert_ast2 {
|
||||||
|
($input:expr, $statements:expr) => {
|
||||||
|
let ast = schala_parser::program($input);
|
||||||
|
let expected = AST { id: Default::default(), statements: $statements.into() };
|
||||||
|
if ast.is_err() {
|
||||||
|
println!("Parse error: {}", ast.unwrap_err());
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
assert_eq!(ast.unwrap(), expected);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! assert_fail {
|
macro_rules! assert_fail {
|
||||||
($input:expr, $failure:expr) => {
|
($input:expr, $failure:expr) => {
|
||||||
let err = parse($input).unwrap_err();
|
let err = parse($input).unwrap_err();
|
||||||
@ -124,15 +135,21 @@ macro_rules! assert_expr {
|
|||||||
|
|
||||||
macro_rules! assert_expr2 {
|
macro_rules! assert_expr2 {
|
||||||
($input:expr, $correct:expr) => {
|
($input:expr, $correct:expr) => {
|
||||||
assert_eq!(schala_parser::expression($input).unwrap(), $correct);
|
let expr = schala_parser::expression($input);
|
||||||
|
if expr.is_err() {
|
||||||
|
println!("Expression parse error: {}", expr.unwrap_err());
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
assert_eq!(expr.unwrap(), $correct);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! assert_fail_expr2 {
|
macro_rules! assert_fail_expr2 {
|
||||||
($input:expr, $failure:expr) => {
|
($input:expr, $failure:expr) => {
|
||||||
let _err = schala_parser::expression($input).unwrap_err();
|
let _err = schala_parser::expression($input).unwrap_err();
|
||||||
//TODO make real tests for failures
|
//TODO make real tests for failures
|
||||||
//assert_eq!(err.to_string(), $failure);
|
//assert_eq!(err.to_string(), $failure);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! assert_fail_expr {
|
macro_rules! assert_fail_expr {
|
||||||
@ -173,17 +190,13 @@ fn binexps() {
|
|||||||
use StatementKind::Expression;
|
use StatementKind::Expression;
|
||||||
|
|
||||||
assert_expr2!("0xf_f_+1", binop("+", expr(NatLiteral(255)), expr(NatLiteral(1))));
|
assert_expr2!("0xf_f_+1", binop("+", expr(NatLiteral(255)), expr(NatLiteral(1))));
|
||||||
assert_eq!(
|
assert_ast2!(
|
||||||
parse("3; 4; 4.3").unwrap(),
|
"3; 4; 4.3",
|
||||||
AST {
|
vec![
|
||||||
id: Default::default(),
|
|
||||||
statements: vec![
|
|
||||||
stmt(Expression(expr(NatLiteral(3)))),
|
stmt(Expression(expr(NatLiteral(3)))),
|
||||||
stmt(Expression(expr(NatLiteral(4)))),
|
stmt(Expression(expr(NatLiteral(4)))),
|
||||||
stmt(Expression(expr(FloatLiteral(4.3)))),
|
stmt(Expression(expr(FloatLiteral(4.3)))),
|
||||||
]
|
]
|
||||||
.into()
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_expr2!(
|
assert_expr2!(
|
||||||
@ -215,21 +228,22 @@ fn binexps() {
|
|||||||
fn prefix_exps() {
|
fn prefix_exps() {
|
||||||
use ExpressionKind::*;
|
use ExpressionKind::*;
|
||||||
|
|
||||||
assert_expr!("-3", prefixop("-", expr(NatLiteral(3))));
|
assert_expr2!("-3", prefixop("-", expr(NatLiteral(3))));
|
||||||
assert_expr!("-0.2", prefixop("-", expr(FloatLiteral(0.2))));
|
assert_expr2!("-0.2", prefixop("-", expr(FloatLiteral(0.2))));
|
||||||
assert_expr!("!3", prefixop("!", expr(NatLiteral(3))));
|
assert_expr2!("!3", prefixop("!", expr(NatLiteral(3))));
|
||||||
assert_expr!("!t", prefixop("!", expr(Value(qn!(t)))));
|
assert_expr2!("!t", prefixop("!", expr(Value(qn!(t)))));
|
||||||
assert_expr!("a <- -b", binop("<-", expr(Value(qn!(a))), prefixop("-", expr(Value(qn!(b))))));
|
//TODO fix
|
||||||
assert_expr!("a <--b", binop("<--", expr(Value(qn!(a))), expr(Value(qn!(b)))));
|
//assert_expr2!("a <- -b", binop("<-", expr(Value(qn!(a))), prefixop("-", expr(Value(qn!(b))))));
|
||||||
|
assert_expr2!("a <--b", binop("<--", expr(Value(qn!(a))), expr(Value(qn!(b)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn operators() {
|
fn operators() {
|
||||||
use ExpressionKind::*;
|
use ExpressionKind::*;
|
||||||
|
|
||||||
assert_expr!("a <- 1", binop("<-", expr(Value(qn!(a))), expr(NatLiteral(1))));
|
assert_expr2!("a <- 1", binop("<-", expr(Value(qn!(a))), expr(NatLiteral(1))));
|
||||||
assert_expr!("a || 1", binop("||", expr(Value(qn!(a))), expr(NatLiteral(1))));
|
assert_expr2!("a || 1", binop("||", expr(Value(qn!(a))), expr(NatLiteral(1))));
|
||||||
assert_expr!("a <> 1", binop("<>", expr(Value(qn!(a))), expr(NatLiteral(1))));
|
assert_expr2!("a <> 1", binop("<>", expr(Value(qn!(a))), expr(NatLiteral(1))));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -270,12 +284,12 @@ fn accessors() {
|
|||||||
fn tuples() {
|
fn tuples() {
|
||||||
use ExpressionKind::*;
|
use ExpressionKind::*;
|
||||||
|
|
||||||
assert_expr!("()", expr(TupleLiteral(vec![])));
|
assert_expr2!("()", expr(TupleLiteral(vec![])));
|
||||||
assert_expr!(
|
assert_expr2!(
|
||||||
r#"("hella", 34)"#,
|
r#"("hella", 34)"#,
|
||||||
expr(TupleLiteral(vec![expr(StringLiteral(rc("hella"))), expr(NatLiteral(34))]))
|
expr(TupleLiteral(vec![expr(StringLiteral(rc("hella"))), expr(NatLiteral(34))]))
|
||||||
);
|
);
|
||||||
assert_expr!(
|
assert_expr2!(
|
||||||
r#"(1+2, "slough")"#,
|
r#"(1+2, "slough")"#,
|
||||||
expr(TupleLiteral(vec![
|
expr(TupleLiteral(vec![
|
||||||
binop("+", expr(NatLiteral(1)), expr(NatLiteral(2))),
|
binop("+", expr(NatLiteral(1)), expr(NatLiteral(2))),
|
||||||
@ -288,11 +302,11 @@ fn tuples() {
|
|||||||
fn identifiers() {
|
fn identifiers() {
|
||||||
use ExpressionKind::*;
|
use ExpressionKind::*;
|
||||||
|
|
||||||
assert_expr!("a", expr(Value(qn!(a))));
|
assert_expr2!("a", expr(Value(qn!(a))));
|
||||||
assert_expr!("some_value", expr(Value(qn!(some_value))));
|
assert_expr2!("some_value", expr(Value(qn!(some_value))));
|
||||||
assert_expr!("alpha::beta::gamma", expr(Value(qn!(alpha, beta, gamma))));
|
assert_expr2!("alpha::beta::gamma", expr(Value(qn!(alpha, beta, gamma))));
|
||||||
assert_expr!("a + b", binop("+", expr(Value(qn!(a))), expr(Value(qn!(b)))));
|
assert_expr2!("a + b", binop("+", expr(Value(qn!(a))), expr(Value(qn!(b)))));
|
||||||
assert_expr!("None", expr(Value(qn!(None))));
|
assert_expr2!("None", expr(Value(qn!(None))));
|
||||||
assert_expr!(
|
assert_expr!(
|
||||||
"thing::item::call()",
|
"thing::item::call()",
|
||||||
expr(Call { f: bx(expr(Value(qn!(thing, item, call)))), arguments: vec![] })
|
expr(Call { f: bx(expr(Value(qn!(thing, item, call)))), arguments: vec![] })
|
||||||
@ -302,14 +316,14 @@ fn identifiers() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn named_struct() {
|
fn named_struct() {
|
||||||
use ExpressionKind::*;
|
use ExpressionKind::*;
|
||||||
assert_expr!(
|
assert_expr2!(
|
||||||
"Pandas { a: x + y }",
|
"Pandas { a: x + y }",
|
||||||
expr(NamedStruct {
|
expr(NamedStruct {
|
||||||
name: qn!(Pandas),
|
name: qn!(Pandas),
|
||||||
fields: vec![(rc("a"), binop("+", expr(Value(qn!(x))), expr(Value(qn!(y)))))]
|
fields: vec![(rc("a"), binop("+", expr(Value(qn!(x))), expr(Value(qn!(y)))))]
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
assert_expr!(
|
assert_expr2!(
|
||||||
"Trousers { a:1, b:800 }",
|
"Trousers { a:1, b:800 }",
|
||||||
expr(NamedStruct {
|
expr(NamedStruct {
|
||||||
name: qn!(Trousers),
|
name: qn!(Trousers),
|
||||||
@ -1067,7 +1081,7 @@ fn if_exprs() {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_expr!(
|
assert_expr2!(
|
||||||
"if a then b else c",
|
"if a then b else c",
|
||||||
expr(IfExpression {
|
expr(IfExpression {
|
||||||
discriminator: Some(bx(expr(Value(qn!(a))))),
|
discriminator: Some(bx(expr(Value(qn!(a))))),
|
||||||
@ -1110,7 +1124,7 @@ fn pattern_matching() {
|
|||||||
use ExpressionKind::*;
|
use ExpressionKind::*;
|
||||||
|
|
||||||
for item in ["if x is Some(a) then { 4 } else { 9 }", "if x is Some(a) then 4 else 9"] {
|
for item in ["if x is Some(a) then { 4 } else { 9 }", "if x is Some(a) then 4 else 9"] {
|
||||||
assert_expr!(
|
assert_expr2!(
|
||||||
item,
|
item,
|
||||||
expr(IfExpression {
|
expr(IfExpression {
|
||||||
discriminator: Some(bx(expr(Value(qn!(x))))),
|
discriminator: Some(bx(expr(Value(qn!(x))))),
|
||||||
@ -1123,7 +1137,7 @@ fn pattern_matching() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_expr!(
|
assert_expr2!(
|
||||||
"if x is Something { a, b: x } then { 4 } else { 9 }",
|
"if x is Something { a, b: x } then { 4 } else { 9 }",
|
||||||
expr(IfExpression {
|
expr(IfExpression {
|
||||||
discriminator: Some(bx(expr(Value(qn!(x))))),
|
discriminator: Some(bx(expr(Value(qn!(x))))),
|
||||||
@ -1138,7 +1152,7 @@ fn pattern_matching() {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_expr!(
|
assert_expr2!(
|
||||||
"if x is -1 then 1 else 2",
|
"if x is -1 then 1 else 2",
|
||||||
expr(IfExpression {
|
expr(IfExpression {
|
||||||
discriminator: Some(bx(expr(Value(qn!(x))))),
|
discriminator: Some(bx(expr(Value(qn!(x))))),
|
||||||
@ -1150,7 +1164,7 @@ fn pattern_matching() {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_expr!(
|
assert_expr2!(
|
||||||
"if x is true then 1 else 2",
|
"if x is true then 1 else 2",
|
||||||
expr(IfExpression {
|
expr(IfExpression {
|
||||||
discriminator: Some(bx(expr(Value(qn!(x))))),
|
discriminator: Some(bx(expr(Value(qn!(x))))),
|
||||||
@ -1162,7 +1176,7 @@ fn pattern_matching() {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_expr!(
|
assert_expr2!(
|
||||||
"if x { is 1 then 5, else 20 }",
|
"if x { is 1 then 5, else 20 }",
|
||||||
expr(IfExpression {
|
expr(IfExpression {
|
||||||
discriminator: Some(bx(expr(Value(qn!(x))))),
|
discriminator: Some(bx(expr(Value(qn!(x))))),
|
||||||
@ -1184,7 +1198,7 @@ fn pattern_matching() {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_expr!(
|
assert_expr2!(
|
||||||
r#"if x is "gnosticism" then 1 else 2"#,
|
r#"if x is "gnosticism" then 1 else 2"#,
|
||||||
expr(IfExpression {
|
expr(IfExpression {
|
||||||
discriminator: Some(bx(expr(Value(qn!(x))))),
|
discriminator: Some(bx(expr(Value(qn!(x))))),
|
||||||
|
@ -247,8 +247,6 @@ impl<'a, 'b> Reducer<'a, 'b> {
|
|||||||
let mut alternatives = vec![];
|
let mut alternatives = vec![];
|
||||||
for arm in condition_arms {
|
for arm in condition_arms {
|
||||||
match arm.condition {
|
match arm.condition {
|
||||||
ast::Condition::Expression(ref _expr) =>
|
|
||||||
return Expression::ReductionError("case-expression".to_string()),
|
|
||||||
ast::Condition::Pattern(ref pat) => {
|
ast::Condition::Pattern(ref pat) => {
|
||||||
let alt = Alternative {
|
let alt = Alternative {
|
||||||
pattern: match pat.reduce(self.symbol_table) {
|
pattern: match pat.reduce(self.symbol_table) {
|
||||||
|
Loading…
Reference in New Issue
Block a user