2020-01-25 11:00:29 -05:00
|
|
|
use std::collections::BTreeMap;
|
|
|
|
use std::iter::Peekable;
|
|
|
|
|
2020-01-26 09:13:39 -05:00
|
|
|
use crate::common::{Scope, Symbol};
|
2020-01-26 13:53:18 -05:00
|
|
|
use crate::utils::{devour_whitespace, devour_whitespace_or_comment};
|
2020-01-26 09:13:39 -05:00
|
|
|
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,
|
2020-01-26 09:13:39 -05:00
|
|
|
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)]
|
2020-01-26 09:13:39 -05:00
|
|
|
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())
|
|
|
|
}
|
|
|
|
|
2020-01-26 09:13:39 -05:00
|
|
|
pub fn get(&self, val: &str) -> Option<&Value> {
|
2020-01-25 11:00:29 -05:00
|
|
|
self.0.get(val)
|
|
|
|
}
|
2020-02-14 11:52:31 -05:00
|
|
|
|
|
|
|
pub fn len(&self) -> usize {
|
|
|
|
self.0.len()
|
|
|
|
}
|
2020-01-25 11:00:29 -05:00
|
|
|
}
|
|
|
|
|
2020-01-26 09:13:39 -05:00
|
|
|
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,
|
2020-01-26 09:13:39 -05:00
|
|
|
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,
|
2020-01-26 09:13:39 -05:00
|
|
|
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 {
|
2020-01-26 09:13:39 -05:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2020-01-26 09:13:39 -05:00
|
|
|
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-26 13:53:18 -05:00
|
|
|
devour_whitespace_or_comment(toks);
|
2020-01-25 11:00:29 -05:00
|
|
|
let mut name: Option<String> = None;
|
|
|
|
let mut val = Vec::new();
|
|
|
|
while let Some(Token { kind, pos }) = toks.next() {
|
|
|
|
match kind {
|
2020-01-26 09:13:39 -05:00
|
|
|
TokenKind::Variable(v) => {
|
2020-01-26 13:53:18 -05:00
|
|
|
devour_whitespace_or_comment(toks);
|
2020-01-26 09:13:39 -05:00
|
|
|
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) => {
|
2020-02-08 17:26:01 -05:00
|
|
|
args.insert(name.clone(), scope.get_var(&v).unwrap().clone())
|
2020-01-26 09:13:39 -05:00
|
|
|
}
|
|
|
|
None => args.insert(
|
|
|
|
format!("{}", args.len()),
|
2020-02-08 17:26:01 -05:00
|
|
|
scope.get_var(&v).unwrap().clone(),
|
2020-01-26 09:13:39 -05:00
|
|
|
),
|
|
|
|
};
|
|
|
|
if let Some(ref mut s) = name {
|
|
|
|
s.clear();
|
|
|
|
}
|
|
|
|
val.clear();
|
|
|
|
}
|
|
|
|
Some(Token {
|
|
|
|
kind: TokenKind::Symbol(Symbol::CloseParen),
|
|
|
|
..
|
|
|
|
}) => {
|
|
|
|
toks.next();
|
|
|
|
match name {
|
2020-02-08 17:26:01 -05:00
|
|
|
Some(name) => args.insert(name, scope.get_var(&v).unwrap().clone()),
|
2020-01-26 09:13:39 -05:00
|
|
|
None => args.insert(
|
|
|
|
format!("{}", args.len()),
|
2020-02-08 17:26:01 -05:00
|
|
|
scope.get_var(&v).unwrap().clone(),
|
2020-01-26 09:13:39 -05:00
|
|
|
),
|
|
|
|
};
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
_ => todo!("unexpected token after variable in call args"),
|
|
|
|
}
|
|
|
|
}
|
2020-01-25 11:00:29 -05:00
|
|
|
TokenKind::Symbol(Symbol::Colon) => {
|
2020-01-26 13:53:18 -05:00
|
|
|
devour_whitespace_or_comment(toks);
|
2020-01-25 11:00:29 -05:00
|
|
|
while let Some(tok) = toks.peek() {
|
|
|
|
match &tok.kind {
|
|
|
|
TokenKind::Symbol(Symbol::Comma) => {
|
|
|
|
toks.next();
|
2020-01-26 09:13:39 -05:00
|
|
|
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) => {
|
2020-01-26 09:13:39 -05:00
|
|
|
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!")),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-02-09 14:27:54 -05:00
|
|
|
TokenKind::Symbol(Symbol::OpenParen) => {
|
|
|
|
val.push(Token { kind, pos });
|
|
|
|
let mut unclosed_parens = 0;
|
|
|
|
while let Some(tok) = toks.next() {
|
|
|
|
match &tok.kind {
|
|
|
|
TokenKind::Symbol(Symbol::OpenParen) => {
|
|
|
|
unclosed_parens += 1;
|
|
|
|
}
|
|
|
|
TokenKind::Symbol(Symbol::CloseParen) => {
|
|
|
|
if unclosed_parens <= 1 {
|
|
|
|
val.push(tok);
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
unclosed_parens -= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
val.push(tok);
|
|
|
|
}
|
|
|
|
}
|
2020-01-25 11:00:29 -05:00
|
|
|
TokenKind::Symbol(Symbol::CloseParen) => {
|
2020-01-26 10:52:43 -05:00
|
|
|
if val.is_empty() {
|
|
|
|
break;
|
|
|
|
}
|
2020-01-25 11:00:29 -05:00
|
|
|
match name {
|
2020-01-26 09:13:39 -05:00
|
|
|
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 {
|
2020-01-26 09:13:39 -05:00
|
|
|
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 }),
|
|
|
|
}
|
2020-01-26 13:53:18 -05:00
|
|
|
devour_whitespace_or_comment(toks);
|
2020-01-25 11:00:29 -05:00
|
|
|
}
|
|
|
|
CallArgs(args)
|
|
|
|
}
|