* obj::Bool builtin type is used for truthiness and decision-making * Branches are compiled and seem to be working for basic integer comparison * Updated version of Shredder to what is current as of writing * CheckTruth VM instruction that will explicitly set the condition flag * Probably some other stuff Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
213 lines
5.5 KiB
Plaintext
213 lines
5.5 KiB
Plaintext
%start Body
|
|
%left '+' '-'
|
|
%left '*' '/'
|
|
%left '<' '>' '<=' '>=' '==' '!='
|
|
%left '&&'
|
|
%left '||'
|
|
|
|
//%avoid_insert "NUM" "SYM" "STRING" "||" "&&" "<" ">" "<=" ">=" "!=" "==" "+" "-" "*" "/" "{"
|
|
|
|
%%
|
|
|
|
Body -> Result<Vec<Stmt>>:
|
|
Body 'EOL' Stmt {
|
|
flatten($1, $3)
|
|
}
|
|
| Body 'EOL' { $1 }
|
|
| Stmt { Ok(vec![$1?]) }
|
|
| { Ok(Vec::new()) }
|
|
;
|
|
|
|
Stmt -> Result<Stmt>:
|
|
Expr { Ok(Stmt::Expr($1?)) }
|
|
| Assign { Ok(Stmt::Assign($1?)) }
|
|
| Return { Ok(Stmt::Return($1?)) }
|
|
;
|
|
|
|
Assign -> Result<AssignStmt>:
|
|
LhsExpr '=' Expr {
|
|
Ok(AssignStmt { lhs: $1?, rhs: $3? })
|
|
}
|
|
;
|
|
|
|
LhsExpr -> Result<LhsExpr>:
|
|
AccessExpr {
|
|
let lhs = match $1? {
|
|
Expr::Access(access) => LhsExpr::SetAttr(*access),
|
|
Expr::Atom(Atom::Ident(local)) => LhsExpr::Name(local),
|
|
_ => todo!("TODO : invalid syntax, raise error"),
|
|
};
|
|
Ok(lhs)
|
|
}
|
|
;
|
|
|
|
Return -> Result<ReturnStmt>:
|
|
'return' Expr { Ok(ReturnStmt { expr: Some($2?), }) }
|
|
| 'return' { Ok(ReturnStmt { expr: None, }) }
|
|
;
|
|
|
|
Expr -> Result<Expr>: BinExpr { $1 };
|
|
|
|
BinExpr -> Result<Expr>:
|
|
BinExpr '||' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Or, $3?)) }
|
|
| BinExpr '&&' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::And, $3?)) }
|
|
| BinExpr '<' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Lt, $3?)) }
|
|
| BinExpr '>' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Gt, $3?)) }
|
|
| BinExpr '<=' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Le, $3?)) }
|
|
| BinExpr '>=' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Ge, $3?)) }
|
|
| BinExpr '==' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Eq, $3?)) }
|
|
| BinExpr '!=' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Neq, $3?)) }
|
|
| BinExpr '*' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Times, $3?)) }
|
|
| BinExpr '/' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Div, $3?)) }
|
|
| BinExpr '+' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Plus, $3?)) }
|
|
| BinExpr '-' BinExpr { Ok(BinExpr::new_expr($1?, BinOp::Minus, $3?)) }
|
|
| UnExpr { $1 }
|
|
;
|
|
|
|
UnExpr -> Result<Expr>:
|
|
'+' UnExpr { Ok(UnExpr::new_expr(UnOp::Plus, $2?)) }
|
|
| '-' UnExpr { Ok(UnExpr::new_expr(UnOp::Minus, $2?)) }
|
|
| CallIndexExpr { $1 }
|
|
;
|
|
|
|
CallIndexExpr -> Result<Expr>:
|
|
IndexExpr { $1 }
|
|
| CallExpr { $1 }
|
|
| AccessExpr { $1 }
|
|
;
|
|
|
|
CallExpr -> Result<Expr>:
|
|
CallIndexExpr '(' FunArgs ')' {
|
|
Ok(CallExpr::new_expr($1?, $3?))
|
|
}
|
|
;
|
|
|
|
FunArgs -> Result<Vec<Expr>>:
|
|
FunArgsTail { $1 }
|
|
| { Ok(Vec::new()) }
|
|
;
|
|
|
|
FunArgsTail -> Result<Vec<Expr>>:
|
|
FunArgsTail ',' Expr { flatten($1, $3) }
|
|
| Expr { Ok(vec![$1?]) }
|
|
;
|
|
|
|
IndexExpr -> Result<Expr>:
|
|
CallIndexExpr '[' Expr ']' {
|
|
Ok(IndexExpr::new_expr($1?, $3?))
|
|
}
|
|
;
|
|
|
|
AccessExpr -> Result<Expr>:
|
|
FunExpr { $1 }
|
|
| CallIndexExpr '.' Ident { Ok(AccessExpr::new_expr($1?, $3?)) }
|
|
;
|
|
|
|
FunExpr -> Result<Expr>:
|
|
IfExpr { $1 }
|
|
| 'fn' '(' FunParams ')' '{' Body '}' { Ok(FunExpr::new_expr($3?, $6?)) }
|
|
;
|
|
|
|
FunParams -> Result<Vec<String>>:
|
|
FunParamsTail { $1 }
|
|
| { Ok(Vec::new()) }
|
|
;
|
|
|
|
FunParamsTail -> Result<Vec<String>>:
|
|
FunParamsTail ',' Ident { flatten($1, $3) }
|
|
| Ident { Ok(vec![$1?]) }
|
|
;
|
|
|
|
IfExpr -> Result<Expr>:
|
|
AtomExpr { $1 }
|
|
| 'if' Expr '{' Body '}' Elif El {
|
|
Ok(IfExpr::new_expr(
|
|
CondBody { cond: $2?, body: $4?, },
|
|
$6?,
|
|
$7?,
|
|
))
|
|
}
|
|
;
|
|
|
|
Elif -> Result<Vec<CondBody>>:
|
|
Elif 'elif' Expr '{' Body '}' {
|
|
let mut head = $1?;
|
|
head.push(CondBody { cond: $3?, body: $5? });
|
|
Ok(head)
|
|
}
|
|
| { Ok(Vec::new()) }
|
|
;
|
|
|
|
El -> Result<Option<Body>>:
|
|
'el' '{' Body '}' { $3.map(Some) }
|
|
| { Ok(None) }
|
|
;
|
|
|
|
AtomExpr -> Result<Expr>:
|
|
Atom { $1.map(Expr::Atom) }
|
|
| '(' Expr ')' { $2 }
|
|
;
|
|
|
|
Atom -> Result<Atom>:
|
|
Ident { Ok(Atom::Ident($1?)) }
|
|
| 'SYM' {
|
|
let v = $1.map_err(|_| ())?;
|
|
let sym = &$lexer.span_str(v.span())[1..];
|
|
Ok(Atom::Sym(sym.to_string()))
|
|
}
|
|
| 'NUM' {
|
|
let v = $1.map_err(|_| ())?;
|
|
let num_text = &$lexer.span_str(v.span());
|
|
Ok(Atom::Num(num_text.parse().unwrap()))
|
|
}
|
|
| 'STRING' {
|
|
let v = $1.map_err(|_| ())?;
|
|
let string = &$lexer.span_str(v.span())[1..];
|
|
Ok(Atom::String(parse_string(string)))
|
|
}
|
|
;
|
|
|
|
Ident -> Result<String>:
|
|
'IDENT' {
|
|
let v = $1.map_err(|_| ())?;
|
|
let ident = $lexer.span_str(v.span()).to_string();
|
|
Ok(ident)
|
|
}
|
|
;
|
|
|
|
%%
|
|
|
|
use crate::syn::ast::*;
|
|
|
|
type Result<T> = std::result::Result<T, ()>;
|
|
|
|
fn flatten<T>(head: Result<Vec<T>>, tail: Result<T>) -> Result<Vec<T>> {
|
|
let mut head = head?;
|
|
let tail = tail?;
|
|
head.push(tail);
|
|
Ok(head)
|
|
}
|
|
|
|
fn parse_string(input: &str) -> String {
|
|
let mut s = String::new();
|
|
let input = &input[..input.bytes().len() - 1];
|
|
let mut chars = input.chars();
|
|
while let Some(c) = chars.next() {
|
|
if c == '\\' {
|
|
let next = chars.next().unwrap();
|
|
let c = match next {
|
|
'\\' => '\\',
|
|
'\'' => '\'',
|
|
'"' => '"',
|
|
'n' => '\n',
|
|
't' => '\t',
|
|
_ => unreachable!(),
|
|
};
|
|
s.push(c);
|
|
} else {
|
|
s.push(c);
|
|
}
|
|
}
|
|
s
|
|
}
|