grass/src/args.rs

244 lines
8.5 KiB
Rust
Raw Normal View History

2020-01-25 11:00:29 -05:00
use std::collections::BTreeMap;
use std::iter::Peekable;
use crate::common::{Scope, Symbol};
2020-01-25 11:00:29 -05:00
use crate::utils::devour_whitespace;
use crate::value::Value;
2020-01-25 11:00:29 -05:00
use crate::{Token, TokenKind};
#[derive(Debug, Clone, Eq, PartialEq)]
pub(crate) struct FuncArgs(pub Vec<FuncArg>);
#[derive(Debug, Clone, Eq, PartialEq)]
pub(crate) struct FuncArg {
pub name: String,
pub default: Option<Value>,
2020-01-25 11:00:29 -05:00
}
impl FuncArgs {
pub const fn new() -> Self {
FuncArgs(Vec::new())
}
}
#[derive(Debug, Clone, std::default::Default)]
pub(crate) struct CallArgs(pub BTreeMap<String, Value>);
2020-01-25 11:00:29 -05:00
impl CallArgs {
pub fn new() -> Self {
CallArgs(BTreeMap::new())
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn get(&self, val: &str) -> Option<&Value> {
2020-01-25 11:00:29 -05:00
self.0.get(val)
}
}
pub(crate) fn eat_func_args<I: Iterator<Item = Token>>(
toks: &mut Peekable<I>,
scope: &Scope,
) -> FuncArgs {
2020-01-25 11:00:29 -05:00
let mut args: Vec<FuncArg> = Vec::new();
devour_whitespace(toks);
while let Some(Token { kind, .. }) = toks.next() {
let name = match kind {
TokenKind::Variable(v) => v,
TokenKind::Symbol(Symbol::CloseParen) => break,
_ => todo!(),
};
let mut default: Vec<Token> = Vec::new();
devour_whitespace(toks);
let kind = match toks.next() {
Some(Token { kind, .. }) => kind,
_ => todo!("unexpected eof"),
};
match kind {
TokenKind::Symbol(Symbol::Colon) => {
devour_whitespace(toks);
while let Some(tok) = toks.peek() {
match &tok.kind {
TokenKind::Symbol(Symbol::Comma) => {
toks.next();
args.push(FuncArg {
name,
default: Some(
Value::from_tokens(&mut default.into_iter().peekable(), scope)
.unwrap(),
),
2020-01-25 11:00:29 -05:00
});
break;
}
TokenKind::Symbol(Symbol::CloseParen) => {
args.push(FuncArg {
name,
default: Some(
Value::from_tokens(&mut default.into_iter().peekable(), scope)
.unwrap(),
),
2020-01-25 11:00:29 -05:00
});
break;
}
_ => {
let tok = toks.next().expect("we know this exists!");
default.push(tok)
}
}
}
}
TokenKind::Symbol(Symbol::Period) => todo!("handle varargs"),
TokenKind::Symbol(Symbol::CloseParen) => {
args.push(FuncArg {
name,
default: if default.is_empty() {
None
} else {
Some(
Value::from_tokens(&mut default.into_iter().peekable(), scope).unwrap(),
)
2020-01-25 11:00:29 -05:00
},
});
break;
}
TokenKind::Symbol(Symbol::Comma) => args.push(FuncArg {
name,
default: None,
}),
_ => {}
}
devour_whitespace(toks);
}
devour_whitespace(toks);
if let Some(Token {
kind: TokenKind::Symbol(Symbol::OpenCurlyBrace),
..
}) = toks.next()
{
} else {
2020-01-25 12:46:51 -05:00
todo!("expected `{{` after args")
2020-01-25 11:00:29 -05:00
}
FuncArgs(args)
}
pub(crate) fn eat_call_args<I: Iterator<Item = Token>>(
toks: &mut Peekable<I>,
scope: &Scope,
) -> CallArgs {
let mut args: BTreeMap<String, Value> = BTreeMap::new();
2020-01-25 11:00:29 -05:00
devour_whitespace(toks);
let mut name: Option<String> = None;
let mut val = Vec::new();
while let Some(Token { kind, pos }) = toks.next() {
match kind {
TokenKind::Variable(v) => {
devour_whitespace(toks);
match toks.peek() {
Some(Token {
kind: TokenKind::Symbol(Symbol::Colon),
..
}) => name = Some(v),
Some(Token {
kind: TokenKind::Symbol(Symbol::Comma),
..
}) => {
toks.next();
match name {
Some(ref name) => {
args.insert(name.clone(), scope.vars.get(&v).unwrap().clone())
}
None => args.insert(
format!("{}", args.len()),
scope.vars.get(&v).unwrap().clone(),
),
};
if let Some(ref mut s) = name {
s.clear();
}
val.clear();
}
Some(Token {
kind: TokenKind::Symbol(Symbol::CloseParen),
..
}) => {
toks.next();
match name {
Some(name) => args.insert(name, scope.vars.get(&v).unwrap().clone()),
None => args.insert(
format!("{}", args.len()),
scope.vars.get(&v).unwrap().clone(),
),
};
break;
}
_ => todo!("unexpected token after variable in call args"),
}
}
2020-01-25 11:00:29 -05:00
TokenKind::Symbol(Symbol::Colon) => {
devour_whitespace(toks);
while let Some(tok) = toks.peek() {
match &tok.kind {
TokenKind::Symbol(Symbol::Comma) => {
toks.next();
args.insert(
name.clone().unwrap(),
Value::from_tokens(&mut val.clone().into_iter().peekable(), scope)
.unwrap(),
);
2020-01-25 11:00:29 -05:00
if let Some(ref mut s) = name {
s.clear();
}
val.clear();
break;
}
TokenKind::Symbol(Symbol::CloseParen) => {
args.insert(
name.clone().unwrap(),
Value::from_tokens(&mut val.clone().into_iter().peekable(), scope)
.unwrap(),
);
2020-01-25 11:00:29 -05:00
break;
}
_ => val.push(toks.next().expect("we know this exists!")),
}
}
}
TokenKind::Symbol(Symbol::CloseParen) => {
match name {
Some(name) => args.insert(
name,
Value::from_tokens(&mut val.into_iter().peekable(), scope).unwrap(),
),
None => args.insert(
format!("{}", args.len()),
Value::from_tokens(&mut val.into_iter().peekable(), scope).unwrap(),
),
2020-01-25 11:00:29 -05:00
};
break;
}
TokenKind::Symbol(Symbol::Comma) => {
match name {
Some(ref name) => args.insert(
name.clone(),
Value::from_tokens(&mut val.clone().into_iter().peekable(), scope).unwrap(),
),
None => args.insert(
format!("{}", args.len()),
Value::from_tokens(&mut val.clone().into_iter().peekable(), scope).unwrap(),
),
2020-01-25 11:00:29 -05:00
};
if let Some(ref mut s) = name {
s.clear();
}
val.clear();
}
_ => val.push(Token { kind, pos }),
}
devour_whitespace(toks);
}
CallArgs(args)
}