Skip to content

Instantly share code, notes, and snippets.

@Marwes
Created July 19, 2015 13:35
Show Gist options
  • Save Marwes/a627a3fcb35ff194c789 to your computer and use it in GitHub Desktop.
Save Marwes/a627a3fcb35ff194c789 to your computer and use it in GitHub Desktop.
extern crate combine;
use combine::{
between,
chainl1,
choice,
char,
digit,
letter,
many,
many1,
ParseError,
parser,
Parser,
ParseResult,
ParserExt,
satisfy,
sep_by,
spaces,
string,
try,
};
use combine::primitives::{
State,
Stream,
};
#[derive(Debug)]
enum Expr {
Int(i32),
Float(f32),
String(String),
Variable(String, Option<Box<Expr>>),
Boolean(bool),
Times(Box<Expr>, Box<Expr>),
Div(Box<Expr>, Box<Expr>),
Plus(Box<Expr>, Box<Expr>),
Minus(Box<Expr>, Box<Expr>),
And(Box<Expr>, Box<Expr>),
Or(Box<Expr>, Box<Expr>),
LessThan(Box<Expr>, Box<Expr>),
LessThanOrEqual(Box<Expr>, Box<Expr>),
GreaterThan(Box<Expr>, Box<Expr>),
GreaterThanOrEqual(Box<Expr>, Box<Expr>),
EqualTo(Box<Expr>, Box<Expr>),
NotEqualTo(Box<Expr>, Box<Expr>),
FunCall(String, Vec<Expr>),
}
#[derive(Debug)]
enum Stmt {
Set(Box<Expr>, Box<Expr>),
Loop(Vec<Stmt>),
}
struct JASSP<I>(::std::marker::PhantomData<fn (I) -> I>);
impl <I> JASSP<I>
where I: Stream<Item=char> {
fn name(input: State<I>) -> ParseResult<String, I> {
let mut name_parser = many1(letter().or(char('_')))
.and(many(letter().or(digit()).or(char('_'))))
.map(|(i, j) : (String, String)|
i + &j
);
name_parser.parse_state(input)
}
fn expr_float(input: State<I>) -> ParseResult<Expr, I> {
let mut float_parser = try(many1(digit())
.skip(char('.'))
.and(many(digit())))
.map(|(i, j) : (String, String)|
Expr::Float((i + "." + &j).parse::<f32>().unwrap())
);
float_parser.parse_state(input)
}
// TODO: add support for strings like this "hello \" you"
fn expr_string(input: State<I>) -> ParseResult<Expr, I> {
let mut string_parser = between(char('"'), char('"'), many(satisfy(|c| c != '"'))).map(|s : String| Expr::String(s));
string_parser.parse_state(input)
}
fn expr_int(input: State<I>) -> ParseResult<Expr, I> {
let mut int_parser = many1(digit())
.map(|i : String|
Expr::Int(i.parse::<i32>().unwrap())
);
int_parser.parse_state(input)
}
fn expr_bool(input: State<I>) -> ParseResult<Expr, I> {
let true_p = string("true").map(|_ : &'static str| Expr::Boolean(true));
let false_p = string("false").map(|_ : &'static str| Expr::Boolean(false));
true_p.or(false_p).parse_state(input)
}
fn expr_variable(input: State<I>) -> ParseResult<Expr, I> {
parser(JASSP::<I>::name)
.map(|i : String| Expr::Variable(i, Option::None))
.parse_state(input)
}
fn expr_variable_array(input: State<I>) -> ParseResult<Expr, I> {
let lex_char = |c : char| char(c).skip(spaces());
try(parser(JASSP::<I>::name).and(between(lex_char('['), lex_char(']'), parser(JASSP::<I>::expr))))
.map(|(i, j) : (String, Expr)| Expr::Variable(i, Option::Some(Box::new(j))))
.parse_state(input)
}
fn expr_parenthesis(input: State<I>) -> ParseResult<Expr, I> {
let lex_char = |c : char| char(c).skip(spaces());
between(lex_char('('), lex_char(')'), parser(JASSP::<I>::expr))
.parse_state(input)
}
fn expr_funcall(input: State<I>) -> ParseResult<Expr, I> {
let lex_char = |c : char| char(c).skip(spaces());
let mut my_parser = try(
parser(JASSP::<I>::name)
.and(
between(
lex_char('('),
lex_char(')'),
sep_by(parser(JASSP::<I>::expr), lex_char(','))
)
)
.map(|(i, j) : (String, Vec<Expr>)| Expr::FunCall(i, j))
);
my_parser.parse_state(input)
}
fn infix_math(input: State<I>) -> ParseResult<Expr, I> {
let lex_char = |c : char| char(c).skip(spaces());
fn times(l: Expr, r: Expr) -> Expr { Expr::Times(Box::new(l), Box::new(r)) };
let times_p = lex_char('*').map(|_| times);
fn div(l: Expr, r: Expr) -> Expr { Expr::Div(Box::new(l), Box::new(r)) };
let div_p = lex_char('/').map(|_| div);
fn plus(l: Expr, r: Expr) -> Expr { Expr::Plus(Box::new(l), Box::new(r)) };
let plus_p = lex_char('+').map(|_| plus);
fn minus(l: Expr, r: Expr) -> Expr { Expr::Minus(Box::new(l), Box::new(r)) };
let minus_p = lex_char('-').map(|_| minus);
chainl1(chainl1(chainl1(chainl1(
parser(JASSP::<I>::expr_non_infix),
times_p), div_p), plus_p), minus_p).parse_state(input)
}
fn infix_numeric_compare(input: State<I>) -> ParseResult<Expr, I> {
let lex_char = |c : char| char(c).skip(spaces());
let lex_string = |s : &'static str| string(s).skip(spaces());
fn lt(l: Expr, r: Expr) -> Expr { Expr::LessThan(Box::new(l), Box::new(r)) };
let lt_p = lex_char('<').map(|_| lt);
fn lte(l: Expr, r: Expr) -> Expr { Expr::LessThanOrEqual(Box::new(l), Box::new(r)) };
let lte_p = lex_string("<=").map(|_| lte);
fn gt(l: Expr, r: Expr) -> Expr { Expr::GreaterThan(Box::new(l), Box::new(r)) };
let gt_p = lex_char('>').map(|_| gt);
fn gte(l: Expr, r: Expr) -> Expr { Expr::GreaterThanOrEqual(Box::new(l), Box::new(r)) };
let gte_p = lex_string(">=").map(|_| gte);
chainl1(chainl1(chainl1(chainl1(
parser(JASSP::<I>::infix_math),
lt_p), lte_p), gt_p), gte_p).parse_state(input)
}
fn infix_equality_compare(input: State<I>) -> ParseResult<Expr, I> {
let lex_string = |s : &'static str| string(s).skip(spaces());
fn eq(l: Expr, r: Expr) -> Expr { Expr::EqualTo(Box::new(l), Box::new(r)) };
let eq_p = lex_string("==").map(|_| eq);
fn neq(l: Expr, r: Expr) -> Expr { Expr::NotEqualTo(Box::new(l), Box::new(r)) };
let neq_p = lex_string("!=").map(|_| neq);
chainl1(chainl1(
parser(JASSP::<I>::infix_numeric_compare),
eq_p), neq_p).parse_state(input)
}
fn infix_boolean_compare(input: State<I>) -> ParseResult<Expr, I> {
let lex_string = |s : &'static str| string(s).skip(spaces());
fn andb(l: Expr, r: Expr) -> Expr { Expr::And(Box::new(l), Box::new(r)) };
let and_p = lex_string("and").map(|_| andb);
fn orb(l: Expr, r: Expr) -> Expr { Expr::Or(Box::new(l), Box::new(r)) };
let or_p = lex_string("or").map(|_| orb);
chainl1(chainl1(
parser(JASSP::<I>::infix_equality_compare),
and_p), or_p).parse_state(input)
}
fn expr_infix(input: State<I>) -> ParseResult<Expr, I> {
parser(JASSP::<I>::infix_boolean_compare).parse_state(input)
}
fn expr_non_infix(input: State<I>) -> ParseResult<Expr, I> {
choice::<&mut [&mut Parser<Input=I, Output=Expr>], _>(&mut [
&mut parser(JASSP::<I>::expr_float),
&mut parser(JASSP::<I>::expr_int),
&mut parser(JASSP::<I>::expr_string),
&mut parser(JASSP::<I>::expr_bool),
&mut parser(JASSP::<I>::expr_funcall),
&mut parser(JASSP::<I>::expr_variable_array),
&mut parser(JASSP::<I>::expr_variable),
&mut parser(JASSP::<I>::expr_parenthesis)
])
.skip(spaces())
.parse_state(input)
}
fn expr(input: State<I>) -> ParseResult<Expr, I> {
parser(JASSP::<I>::expr_infix)
.or(parser(JASSP::<I>::expr_non_infix))
.parse_state(input)
}
fn stmt_set(input: State<I>) -> ParseResult<Stmt, I> {
let lhs = parser(JASSP::<I>::expr_variable_array)
.or(parser(JASSP::<I>::expr_variable));
let rhs = parser(JASSP::<I>::expr);
try((string("set"), spaces(), lhs, spaces(), char('='), spaces(), rhs))
.map(|t| Stmt::Set(Box::new(t.2), Box::new(t.6)))
.parse_state(input)
}
fn stmt_loop(input: State<I>) -> ParseResult<Stmt, I> {
let stmts = parser(JASSP::<I>::stmts);
(string("loop"), spaces(), stmts, spaces(), string("endloop"), spaces())
.map(|t| Stmt::Loop(t.2))
.parse_state(input)
}
fn stmt(input: State<I>) -> ParseResult<Stmt, I> {
parser(JASSP::<I>::stmt_set)
.or(parser(JASSP::<I>::stmt_loop))
.parse_state(input)
}
fn stmts(input: State<I>) -> ParseResult<Vec<Stmt>, I> {
sep_by(parser(JASSP::<I>::stmt), spaces())
.parse_state(input)
}
}
fn main() {
let input = "set job[27] = horse + 5 * ( 5 + 1 ) + john( 27 , 3 ) set x = 2";
let result2 : Result<(Vec<Stmt>, &str), ParseError<char>> = parser(JASSP::stmts).parse(input);
match result2 {
Ok((value, _remaining_input)) => println!("Result: {:?}, Remain: {:?}", value, _remaining_input),
Err(err) => println!("Err: {}", err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment