// Copyright 2017 Jeremy Wall // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! The Parsing stage of the ucg compiler. use std; use std::borrow::Borrow; use std::str::FromStr; use abortable_parser; use abortable_parser::combinators::eoi; use abortable_parser::iter::SliceIter; use abortable_parser::{Error, Peekable, Result}; use self::precedence::op_expression; use crate::ast::*; use crate::error::BuildError; use crate::iter::OffsetStrIter; use crate::tokenizer::*; pub use crate::tokenizer::{CommentGroup, CommentMap}; type ParseResult<'a, O> = Result, O>; #[cfg(feature = "tracing")] const ENABLE_TRACE: bool = true; #[cfg(not(feature = "tracing"))] const ENABLE_TRACE: bool = false; type ConvertResult<'a, O> = std::result::Result>>; macro_rules! trace_parse { ($i:expr, $rule:ident!( $($args:tt)* )) => { { use crate::parse::ENABLE_TRACE; if ENABLE_TRACE { eprintln!("Entering Rule: {:?} {:?}", stringify!($rule), $i); } let result = $rule!($i, $($args)* ); if ENABLE_TRACE { eprintln!("Exiting Rule: {:?} with {:?}", stringify!($rule), result); } result } }; ($i:expr, $rule:ident) => { { use crate::parse::ENABLE_TRACE; if ENABLE_TRACE { eprintln!("Entering Rule: {:?} {:?}", stringify!($rule), $i); } let result = run!($i, $rule); if ENABLE_TRACE { eprintln!("Exiting Rule: {:?} with {:?}", stringify!($rule), result); } result } }; } fn symbol_to_value(s: &Token) -> ConvertResult { Ok(Value::Symbol(value_node!( s.fragment.to_string(), s.pos.clone() ))) } // symbol is a bare unquoted field. make_fn!( symbol, Value>, match_type!(BAREWORD => symbol_to_value) ); fn str_to_value(s: &Token) -> ConvertResult { Ok(Value::Str(value_node!( s.fragment.to_string(), s.pos.clone() ))) } // quoted_value is a quoted string. make_fn!( quoted_value, Value>, match_type!(STR => str_to_value) ); // Helper function to make the return types work for down below. fn triple_to_number<'a>( input: SliceIter<'a, Token>, v: (Option, Option, Option), ) -> ConvertResult<'a, Value> { let (pref, mut pref_pos) = match v.0 { None => ("", Position::new(0, 0, 0)), Some(ref bs) => (bs.fragment.borrow(), bs.pos.clone()), }; let has_dot = v.1.is_some(); if v.0.is_some() && !has_dot && v.2.is_none() { let i = match FromStr::from_str(pref) { Ok(i) => i, Err(_) => { return Err(Error::new( format!("Not an integer! {}", pref), Box::new(input.clone()), )); } }; return Ok(Value::Int(value_node!(i, pref_pos))); } if v.0.is_none() && has_dot { pref_pos = v.1.unwrap().pos; } let suf = match v.2 { None => "".to_string(), Some(bs) => bs.fragment, }; let to_parse = pref.to_string() + "." + &suf; let f = match FromStr::from_str(&to_parse) { Ok(f) => f, Err(_) => { return Err(Error::new( format!("Not a float! {}", to_parse), Box::new(input.clone()), )); } }; return Ok(Value::Float(value_node!(f, pref_pos))); } // trace_macros!(true); // NOTE(jwall): HERE THERE BE DRAGONS. The order for these matters // alot. We need to process alternatives in order of decreasing // specificity. Unfortunately this means we are required to go in a // decreasing size order which messes with either!'s completion logic. To // work around this we have to force Incomplete to be Error so that // either! will try the next in the series instead of aborting. // // *IMPORTANT* // It also means this combinator is risky when used with partial // inputs. So handle with care. fn number(input: SliceIter) -> Result, Value> { let parsed = do_each!(input, num => either!( complete!( "Not a float", do_each!( // 1.0 prefix => match_type!(DIGIT), has_dot => punct!("."), suffix => match_type!(DIGIT), (Some(prefix.clone()), Some(has_dot.clone()), Some(suffix.clone())) )), complete!( "Not a float", do_each!( // 1. prefix => match_type!(DIGIT), has_dot => punct!("."), (Some(prefix.clone()), Some(has_dot.clone()), None) )), complete!( "Not a float", do_each!( // .1 has_dot => punct!("."), suffix => match_type!(DIGIT), (None, Some(has_dot.clone()), Some(suffix.clone())) )), do_each!( // 1 prefix => match_type!(DIGIT), (Some(prefix.clone()), None, None) )), (num) ); match parsed { Result::Abort(e) => Result::Abort(e), Result::Fail(e) => Result::Fail(e), Result::Incomplete(offset) => Result::Incomplete(offset), Result::Complete(rest, triple) => { let num = triple_to_number(rest.clone(), triple); match num { Ok(val) => Result::Complete(rest, val), Err(e) => Result::Fail(e), } } } } // trace_macros!(false); make_fn!( boolean_value, Value>, do_each!( b => match_type!(BOOLEAN), (Value::Boolean(PositionedItem{ val: b.fragment == "true", pos: b.pos, })) ) ); make_fn!( field_value, (Token, Expression)>, do_each!( field => wrap_err!(either!(match_type!(BOOLEAN), match_type!(BAREWORD), match_type!(STR)), "Field names must be a bareword or a string."), _ => must!(punct!("=")), value => must!(expression), (field, value) ) ); // Helper function to make the return types work for down below. fn vec_to_tuple(pos: Position, fields: Option) -> Value { Value::Tuple(value_node!(fields.unwrap_or(Vec::new()), pos)) } make_fn!( field_list, FieldList>, separated!(punct!(","), field_value) ); make_fn!( tuple, Value>, do_each!( pos => pos, _ => punct!("{"), v => optional!(field_list), _ => optional!(punct!(",")), _ => must!(punct!("}")), (vec_to_tuple(pos, v)) ) ); fn tuple_to_list>(pos: Sp, elems: Option>) -> Value { Value::List(ListDef { elems: elems.unwrap_or_else(|| Vec::new()), pos: pos.into(), }) } make_fn!( list_value, Value>, do_each!( start => punct!("["), elements => optional!(separated!(punct!(","), expression)), _ => optional!(punct!(",")), _ => must!(punct!("]")), (tuple_to_list(start.pos, elements)) ) ); make_fn!( empty_value, Value>, do_each!( pos => pos, _ => match_type!(EMPTY), (Value::Empty(pos.into())) ) ); make_fn!( compound_value, Value>, either!(trace_parse!(list_value), trace_parse!(tuple)) ); make_fn!( value, Value>, either!( trace_parse!(symbol), trace_parse!(compound_value), trace_parse!(boolean_value), trace_parse!(empty_value), trace_parse!(number), trace_parse!(quoted_value) ) ); fn value_to_expression(v: Value) -> Expression { Expression::Simple(v) } make_fn!( simple_expression, Expression>, do_each!( val => trace_parse!(value), _ => not!(either!(punct!("{"), punct!("["), punct!("("))), (value_to_expression(val)) ) ); fn expression_to_grouped_expression(e: Expression, pos: Position) -> Expression { Expression::Grouped(Box::new(e), pos) } make_fn!( grouped_expression, Expression>, do_each!( pos => pos, _ => punct!("("), expr => do_each!( expr => trace_parse!(expression), _ => must!(punct!(")")), (expr) ), (expression_to_grouped_expression(expr, pos)) ) ); fn tuple_to_copy(sym: Value, fields: Option) -> Expression { let pos = sym.pos().clone(); let fields = match fields { Some(fields) => fields, None => Vec::new(), }; Expression::Copy(CopyDef { selector: sym, fields: fields, pos: pos, }) } make_fn!( copy_expression, Expression>, do_each!( sym => trace_parse!(symbol), _ => punct!("{"), fields => optional!(trace_parse!(field_list)), _ => optional!(punct!(",")), _ => must!(punct!("}")), (tuple_to_copy(sym, fields)) ) ); fn tuple_to_func<'a>( pos: Position, vals: Option>, val: Expression, ) -> ConvertResult<'a, Expression> { let mut default_args = match vals { None => Vec::new(), Some(vals) => vals, }; let arglist = default_args .drain(0..) .map(|s| PositionedItem { pos: s.pos().clone(), val: s.to_string(), }) .collect(); Ok(Expression::Func(FuncDef { scope: None, argdefs: arglist, fields: Box::new(val), pos: pos, })) } make_fn!( arglist, Vec>, separated!(punct!(","), symbol) ); fn module_expression(input: SliceIter) -> Result, Expression> { let parsed = do_each!(input, pos => pos, _ => word!("module"), _ => must!(punct!("{")), arglist => trace_parse!(optional!(field_list)), _ => optional!(punct!(",")), _ => must!(punct!("}")), _ => must!(punct!("=>")), out_expr => optional!( do_each!( _ => punct!("("), expr => must!(expression), _ => must!(punct!(")")), (expr) ) ), _ => must!(punct!("{")), stmt_list => trace_parse!(repeat!(statement)), _ => must!(punct!("}")), (pos, arglist, out_expr, stmt_list) ); match parsed { Result::Abort(e) => Result::Abort(e), Result::Fail(e) => Result::Fail(e), Result::Incomplete(offset) => Result::Incomplete(offset), Result::Complete(rest, (pos, arglist, out_expr, stmt_list)) => { let mut def = ModuleDef::new(arglist.unwrap_or_else(|| Vec::new()), stmt_list, pos); if let Some(expr) = out_expr { def.set_out_expr(expr); } //eprintln!( // "module def at: {:?} arg_typle len {} stmts len {}", // def.pos, // def.arg_set.len(), // def.statements.len() //); Result::Complete(rest, Expression::Module(def)) } } } fn func_expression(input: SliceIter) -> Result, Expression> { let parsed = do_each!(input, pos => pos, _ => word!("func"), _ => must!(punct!("(")), arglist => trace_parse!(optional!(arglist)), _ => must!(punct!(")")), _ => must!(punct!("=>")), map => trace_parse!(expression), (pos, arglist, map) ); match parsed { Result::Abort(e) => Result::Abort(e), Result::Fail(e) => Result::Fail(e), Result::Incomplete(offset) => Result::Incomplete(offset), Result::Complete(rest, (pos, arglist, map)) => match tuple_to_func(pos, arglist, map) { Ok(expr) => Result::Complete(rest, expr), Err(e) => Result::Fail(Error::caused_by( "Invalid func syntax", Box::new(e), Box::new(rest.clone()), )), }, } } make_fn!( alt_select_expression, Expression>, do_each!( pos => pos, _ => word!("select"), _ => must!(punct!("(")), val => must!(expression), default => optional!( do_each!( _ => punct!(","), def => must!(expression), (def) ) ), _ => optional!(punct!(",")), _ => must!(punct!(")")), _ => must!(punct!("=>")), _ => must!(punct!("{")), tpl => must!(field_list), _ => optional!(punct!(",")), _ => must!(punct!("}")), (Expression::Select(SelectDef { val: Box::new(val), default: default.map(|e| Box::new(e)), tuple: tpl, pos: pos, })) ) ); make_fn!( simple_format_args, FormatArgs>, do_each!( _ => punct!("("), args => separated!(punct!(","), trace_parse!(expression)), _ => must!(punct!(")")), (FormatArgs::List(args)) ) ); make_fn!( expression_format_args, FormatArgs>, do_each!( expr => must!(expression), (FormatArgs::Single(Box::new(expr))) ) ); make_fn!( format_expression, Expression>, do_each!( tmpl => match_type!(STR), _ => punct!("%"), args => wrap_err!(must!(either!(simple_format_args, expression_format_args)), "Expected format arguments"), (Expression::Format(FormatDef { template: tmpl.fragment.to_string(), args: args, pos: tmpl.pos, })) ) ); make_fn!( include_expression, Expression>, do_each!( pos => pos, _ => word!("include"), typ => must!(match_type!(BAREWORD)), path => must!(match_type!(STR)), (Expression::Include(IncludeDef{ pos: pos, typ: typ, path: path, })) ) ); fn tuple_to_call<'a>( input: SliceIter<'a, Token>, val: Value, exprs: Option>, ) -> ConvertResult<'a, Expression> { if let Value::Symbol(_) = val { Ok(Expression::Call(CallDef { funcref: val, arglist: exprs.unwrap_or_else(|| Vec::new()), pos: (&input).into(), })) } else { Err(Error::new( format!("Expected Selector Got {:?}", val), Box::new(input.clone()), )) } } make_fn!( cast_expression, Expression>, do_each!( typ => either!( word!("int"), word!("float"), word!("str"), word!("bool") ), _ => punct!("("), expr => expression, _ => punct!(")"), (Expression::Cast(CastDef{ cast_type: match typ.fragment.as_str() { "int" => CastType::Int, "float" => CastType::Float, "str" => CastType::Str, "bool" => CastType::Bool, _ => unreachable!(), }, target: Box::new(expr), pos: typ.pos, })) ) ); fn call_expression(input: SliceIter) -> Result, Expression> { let parsed = do_each!(input.clone(), callee_name => trace_parse!(symbol), _ => punct!("("), args => optional!(separated!(punct!(","), trace_parse!(expression))), _ => optional!(punct!(",")), _ => must!(punct!(")")), (callee_name, args) ); match parsed { Result::Abort(e) => Result::Abort(e), Result::Fail(e) => Result::Fail(e), Result::Incomplete(offset) => Result::Incomplete(offset), Result::Complete(rest, (name, args)) => match tuple_to_call(input.clone(), name, args) { Ok(expr) => Result::Complete(rest, expr), Err(e) => Result::Fail(Error::caused_by( "Invalid Call Syntax", Box::new(e), Box::new(rest), )), }, } } make_fn!( reduce_expression, Expression>, do_each!( pos => pos, _ => word!("reduce"), _ => must!(punct!("(")), func => must!(expression), _ => must!(punct!(",")), acc => must!(trace_parse!(expression)), _ => must!(punct!(",")), tgt => must!(trace_parse!(expression)), _ => optional!(punct!(",")), _ => must!(punct!(")")), (Expression::FuncOp(FuncOpDef::Reduce(ReduceOpDef{ func: Box::new(func), acc: Box::new(acc), target: Box::new(tgt), pos: pos, }))) ) ); make_fn!( map_expression, Expression>, do_each!( pos => pos, _ => word!("map"), _ => must!(punct!("(")), func => must!(expression), _ => must!(punct!(",")), list => must!(trace_parse!(expression)), _ => optional!(punct!(",")), _ => must!(punct!(")")), (Expression::FuncOp(FuncOpDef::Map(MapFilterOpDef{ func: Box::new(func), target: Box::new(list), pos: pos, }))) ) ); make_fn!( filter_expression, Expression>, do_each!( pos => pos, _ => word!("filter"), _ => must!(punct!("(")), func => must!(expression), _ => must!(punct!(",")), list => must!(trace_parse!(expression)), _ => optional!(punct!(",")), _ => must!(punct!(")")), (Expression::FuncOp(FuncOpDef::Filter(MapFilterOpDef{ func: Box::new(func), target: Box::new(list), pos: pos, }))) ) ); make_fn!( func_op_expression, Expression>, either!(reduce_expression, map_expression, filter_expression) ); make_fn!( range_expression, Expression>, do_each!( pos => pos, start => either!(simple_expression, grouped_expression), _ => punct!(":"), maybe_step => optional!( do_each!( step => either!(simple_expression, grouped_expression), _ => punct!(":"), (Box::new(step)) ) ), end => must!(wrap_err!(either!(simple_expression, grouped_expression), "Expected simple or grouped expression")), (Expression::Range(RangeDef{ pos: pos, start: Box::new(start), step: maybe_step, end: Box::new(end), })) ) ); make_fn!( import_expression, Expression>, do_each!( pos => pos, _ => word!("import"), path => must!(wrap_err!(match_type!(STR), "Expected import path")), (Expression::Import(ImportDef{ pos: pos, path: path, })) ) ); make_fn!( string_expression, Expression>, do_each!( val => trace_parse!(quoted_value), (value_to_expression(val)) ) ); make_fn!( fail_expression, Expression>, do_each!( pos => pos, _ => word!("fail"), msg => must!(wrap_err!(expression, "Expected failure message")), (Expression::Fail(FailDef{ pos: pos, message: Box::new(msg), })) ) ); make_fn!( trace_expression, Expression>, do_each!( pos => pos, _ => word!("TRACE"), expr => must!(wrap_err!(expression, "Expected failure message")), (Expression::Debug(DebugDef{ pos: pos, expr: Box::new(expr), })) ) ); make_fn!( not_expression, Expression>, do_each!( pos => pos, _ => word!("not"), expr => must!(wrap_err!(expression, "Expected failure message")), (Expression::Not(NotDef{ pos: pos, expr: Box::new(expr), })) ) ); fn unprefixed_expression(input: SliceIter) -> ParseResult { let _input = input.clone(); either!( input, trace_parse!(format_expression), trace_parse!(range_expression), trace_parse!(simple_expression), // cast parse attempts must happen before call parse attempts. trace_parse!(cast_expression), trace_parse!(call_expression), trace_parse!(copy_expression) ) } make_fn!( non_op_expression, Expression>, either!( trace_parse!(func_op_expression), trace_parse!(func_expression), trace_parse!(import_expression), trace_parse!(trace_expression), trace_parse!(not_expression), trace_parse!(fail_expression), trace_parse!(module_expression), trace_parse!(alt_select_expression), trace_parse!(grouped_expression), trace_parse!(include_expression), trace_parse!(unprefixed_expression) ) ); pub fn expression(input: SliceIter) -> ParseResult { let _input = input.clone(); match trace_parse!(_input, op_expression) { Result::Incomplete(i) => Result::Incomplete(i), Result::Fail(_) => trace_parse!(input, non_op_expression), Result::Abort(e) => Result::Abort(e), Result::Complete(rest, expr) => Result::Complete(rest, expr), } } make_fn!( expression_statement, Statement>, do_each!( e => do_each!( expr => trace_parse!(expression), _ => must!(punct!(";")), (expr) ), (Statement::Expression(e)) ) ); make_fn!( let_stmt_body, Statement>, do_each!( pos => pos, name => wrap_err!(match_type!(BAREWORD), "Expected name for binding"), _ => punct!("="), val => trace_parse!(wrap_err!(expression, "Expected Expression to bind")), _ => punct!(";"), (Statement::Let(LetDef { pos: pos, name: name, value: val, })) ) ); make_fn!( let_statement, Statement>, do_each!( _ => word!("let"), stmt => trace_parse!(must!(let_stmt_body)), (stmt) ) ); make_fn!( assert_statement, Statement>, do_each!( pos => pos, _ => word!("assert"), expr => wrap_err!(must!(expression), "Expected Tuple {ok=, desc=}"), _ => must!(punct!(";")), (Statement::Assert(pos, expr)) ) ); make_fn!( out_statement, Statement>, do_each!( pos => pos, _ => word!("out"), typ => wrap_err!(must!(match_type!(BAREWORD)), "Expected converter name"), expr => wrap_err!(must!(expression), "Expected Expression to export"), _ => must!(punct!(";")), (Statement::Output(pos, typ.clone(), expr.clone())) ) ); make_fn!( print_statement, Statement>, do_each!( pos => pos, _ => word!("convert"), typ => wrap_err!(must!(match_type!(BAREWORD)), "Expected converter name"), expr => wrap_err!(must!(expression), "Expected Expression to print"), _ => must!(punct!(";")), (Statement::Print(pos, typ.clone(), expr.clone())) ) ); //trace_macros!(true); fn statement(i: SliceIter) -> Result, Statement> { return either!( i, trace_parse!(assert_statement), trace_parse!(let_statement), trace_parse!(out_statement), trace_parse!(print_statement), trace_parse!(expression_statement) ); } //trace_macros!(false); /// Parses a LocatedSpan into a list of Statements or an `error::Error`. pub fn parse<'a>( input: OffsetStrIter<'a>, comment_map: Option<&mut CommentMap>, ) -> std::result::Result, BuildError> { match tokenize(input.clone(), comment_map) { Ok(tokenized) => { let mut out = Vec::new(); let mut i_ = SliceIter::new(&tokenized); loop { let i = i_.clone(); if let Some(tok) = i.peek_next() { if tok.typ == TokenType::END { break; } } match statement(i.clone()) { Result::Abort(e) => { return Err(BuildError::from(e)); } Result::Fail(e) => { return Err(BuildError::from(e)); } Result::Incomplete(_ei) => { let err = abortable_parser::Error::new( "Unexpected end of parse input", Box::new(i.clone()), ); return Err(BuildError::from(err)); } Result::Complete(rest, stmt) => { out.push(stmt); i_ = rest; if eoi(i).is_complete() { break; } } } } return Ok(out); } Err(e) => { return Err(e); } } } pub mod precedence;